From aac61f688b54116d2e253ceb9a6580b62f71081b Mon Sep 17 00:00:00 2001 From: shenweiyan Date: Sat, 9 Nov 2024 19:02:48 +0000 Subject: [PATCH] Add Changes By GitHub Actions: 2024-11-10 03:02:48 (CST/UTC-8) --- docs/Discussions.txt | 2 +- update.log | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/Discussions.txt b/docs/Discussions.txt index 0c69edf807..4e2bdb88ef 100644 --- a/docs/Discussions.txt +++ b/docs/Discussions.txt @@ -1 +1 @@ -{'date': '2024-11-09 03:03:14.298576+08:00', 'nodes': [{'title': 'GitHub Actions 更新 Submodule', 'number': 93, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/93', 'createdAt': '2024-11-06T03:31:21Z', 'lastEditedAt': None, 'updatedAt': '2024-11-06T03:31:22Z', 'body': '怎么通过 GitHub Actions 实时更新 Git 仓库中的子模块(submodules)。\r\n\r\n\r\n\r\n```yaml\r\nname: Send submodule updates to parent repo\r\n\r\non:\r\n push:\r\n branches: \r\n - main\r\n\r\njobs:\r\n update:\r\n runs-on: ubuntu-latest\r\n\r\n steps:\r\n - uses: actions/checkout@v2\r\n with: \r\n repository: xxx/parent_xxx\r\n token: ${{ secrets.PRIVATE_TOKEN_GITHUB }}\r\n\r\n - name: Pull & update submodules recursively\r\n run: |\r\n git submodule update --init --recursive\r\n git submodule update --recursive --remote\r\n - name: Commit\r\n run: |\r\n git config user.email "actions@github.com"\r\n git config user.name "GitHub Actions - update submodules"\r\n git add --all\r\n git commit -m "Update submodules" || echo "No changes to commit"\r\n git push\r\n```\r\n\r\n1. `git submodule update --init --recursive`\r\n\r\n这个命令用于初始化并更新仓库中的子模块。具体来说:\r\n\r\n- `--init` 参数会初始化在 `.gitmodules` 文件中指定的每个子模块的配置信息,但不会更新子模块的内容。这个步骤是必须的,因为 Git 不会自动初始化子模块的配置信息。\r\n- `--recursive` 参数确保命令递归地应用于任何嵌套的子模块。这意味着如果子模块本身还包含子模块,这些子模块也会被初始化。\r\n\r\n简而言之,这个命令会初始化仓库中所有(包括嵌套的)子模块的配置,并更新它们到在父仓库中记录的提交。\r\n\r\n2. `git submodule update --recursive --remote`\r\n\r\n这个命令用于更新仓库中的子模块到它们的远程仓库中的最新状态(或指定的分支/标签)。具体来说:\r\n\r\n- `--recursive` 的作用与上述命令相同,确保命令递归地应用于所有嵌套的子模块。\r\n- `--remot`e 参数指示 Git 更新每个子模块到其远程仓库的当前分支的最新提交。如果没有指定分支,则默认为在 `.gitmodules ` 文件中为每个子模块指定的分支。\r\n\r\n注意,这个命令并不会改变父仓库中记录的子模块的提交。它只是更新了子模块的工作目录和索引,以匹配远程仓库的最新状态。如果你想在父仓库中记录这些更新,你需要在子模块中执行提交,然后回到父仓库中,添加子模块的变更并提交。\r\n\r\n3. 总结\r\n\r\n- `git submodule update --init --recursive` 用于初始化并更新子模块到父仓库中记录的提交。\r\n- `git submodule update --recursive --remote` 用于将子模块更新到其远程仓库的最新状态,但不会在父仓库中记录这些更新。\r\n', 'bodyText': '怎么通过 GitHub Actions 实时更新 Git 仓库中的子模块(submodules)。\n\nname: Send submodule updates to parent repo\n\non:\n push:\n branches: \n - main\n\njobs:\n update:\n runs-on: ubuntu-latest\n\n steps:\n - uses: actions/checkout@v2\n with: \n repository: xxx/parent_xxx\n token: ${{ secrets.PRIVATE_TOKEN_GITHUB }}\n\n - name: Pull & update submodules recursively\n run: |\n git submodule update --init --recursive\n git submodule update --recursive --remote\n - name: Commit\n run: |\n git config user.email "actions@github.com"\n git config user.name "GitHub Actions - update submodules"\n git add --all\n git commit -m "Update submodules" || echo "No changes to commit"\n git push\n\ngit submodule update --init --recursive\n\n这个命令用于初始化并更新仓库中的子模块。具体来说:\n\n--init 参数会初始化在 .gitmodules 文件中指定的每个子模块的配置信息,但不会更新子模块的内容。这个步骤是必须的,因为 Git 不会自动初始化子模块的配置信息。\n--recursive 参数确保命令递归地应用于任何嵌套的子模块。这意味着如果子模块本身还包含子模块,这些子模块也会被初始化。\n\n简而言之,这个命令会初始化仓库中所有(包括嵌套的)子模块的配置,并更新它们到在父仓库中记录的提交。\n\ngit submodule update --recursive --remote\n\n这个命令用于更新仓库中的子模块到它们的远程仓库中的最新状态(或指定的分支/标签)。具体来说:\n\n--recursive 的作用与上述命令相同,确保命令递归地应用于所有嵌套的子模块。\n--remote 参数指示 Git 更新每个子模块到其远程仓库的当前分支的最新提交。如果没有指定分支,则默认为在 .gitmodules 文件中为每个子模块指定的分支。\n\n注意,这个命令并不会改变父仓库中记录的子模块的提交。它只是更新了子模块的工作目录和索引,以匹配远程仓库的最新状态。如果你想在父仓库中记录这些更新,你需要在子模块中执行提交,然后回到父仓库中,添加子模块的变更并提交。\n\n总结\n\n\ngit submodule update --init --recursive 用于初始化并更新子模块到父仓库中记录的提交。\ngit submodule update --recursive --remote 用于将子模块更新到其远程仓库的最新状态,但不会在父仓库中记录这些更新。', 'bodyHTML': '

怎么通过 GitHub Actions 实时更新 Git 仓库中的子模块(submodules)。

\n\n
name: Send submodule updates to parent repo\n\non:\n  push:\n    branches: \n      - main\n\njobs:\n  update:\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v2\n        with: \n          repository: xxx/parent_xxx\n          token: ${{ secrets.PRIVATE_TOKEN_GITHUB }}\n\n      - name: Pull & update submodules recursively\n        run: |\n          git submodule update --init --recursive\n          git submodule update --recursive --remote\n      - name: Commit\n        run: |\n          git config user.email "actions@github.com"\n          git config user.name "GitHub Actions - update submodules"\n          git add --all\n          git commit -m "Update submodules" || echo "No changes to commit"\n          git push
\n
    \n
  1. git submodule update --init --recursive
  2. \n
\n

这个命令用于初始化并更新仓库中的子模块。具体来说:

\n\n

简而言之,这个命令会初始化仓库中所有(包括嵌套的)子模块的配置,并更新它们到在父仓库中记录的提交。

\n
    \n
  1. git submodule update --recursive --remote
  2. \n
\n

这个命令用于更新仓库中的子模块到它们的远程仓库中的最新状态(或指定的分支/标签)。具体来说:

\n\n

注意,这个命令并不会改变父仓库中记录的子模块的提交。它只是更新了子模块的工作目录和索引,以匹配远程仓库的最新状态。如果你想在父仓库中记录这些更新,你需要在子模块中执行提交,然后回到父仓库中,添加子模块的变更并提交。

\n
    \n
  1. 总结
  2. \n
\n', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '1.3.18-版本控制'}]}, 'comments': {'nodes': []}}, {'title': 'Follow 初体验', 'number': 92, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/92', 'createdAt': '2024-10-29T09:10:42Z', 'lastEditedAt': '2024-10-31T03:00:25Z', 'updatedAt': '2024-10-31T03:00:25Z', 'body': '在 2024 年国庆前后的这一段时间,[Follow](https://follow.is/) 的这个号称 Next-Gen Information Browser 的 RSS 阅读器在各大平台相当的火,各种疯抢激活码的帖子也是起此彼伏。直到 10 月 24,开始公测,上去体验了一下,发现也就跟其它 RSS 软件没啥太大区别,并没有说的那么玄乎。\r\n\r\n\r\n\r\n## 卡顿\r\n\r\n有人提到的公测遇到的第一个问题 **"卡"**,加载缓慢。这个问题,我也感受到了,我一直用的 Web 版本,刚开始的时候的确不够流畅。有人说这跟代理工具和节点有关,通过更换工具和节点解决。\r\n\r\n## 解析异常\r\n\r\n一个 RSS 最核心的还是要能订阅并正常获取并解析订阅源的内容。这一点 Follow 给我的感觉不好。在订阅 [袁凡](https://yuanfan.rbind.io/) 老师的博客,就出现了无法正常解析。 \r\n![follow-earfanfan](https://kg.weiyan.cc/2024/10/follow-earfanfan.png)\r\n\r\n同样的订阅,在 [QiReader](https://github.com/shenweiyan/Knowledge-Garden/discussions/73) 上却表现很好。 \r\n![qireader-earfanfan](https://kg.weiyan.cc/2024/10/qireader-earfanfan.png)\r\n\r\n\r\n## 列表赚钱\r\n\r\n> 之前为什么水军这么多到处发订阅列表,今天用了下才知道原来 RSS 列表真的可以赚钱。第一次见到这种创新,和之前的饥饿营销绝配了。然而阅读器本身做得不怎样。 \r\n\r\n很同意这个评论,对于这一种赚钱方式,的确第一次见到。\r\n\r\n## 其他看法\r\n\r\n在细节处理,希望这一款 **Next-Gen Information Browser** 继续打磨。\r\n\r\n![follow-joe-hou](https://kg.weiyan.cc/2024/10/follow-joe-hou.png)', 'bodyText': '在 2024 年国庆前后的这一段时间,Follow 的这个号称 Next-Gen Information Browser 的 RSS 阅读器在各大平台相当的火,各种疯抢激活码的帖子也是起此彼伏。直到 10 月 24,开始公测,上去体验了一下,发现也就跟其它 RSS 软件没啥太大区别,并没有说的那么玄乎。\n\n卡顿\n有人提到的公测遇到的第一个问题 "卡",加载缓慢。这个问题,我也感受到了,我一直用的 Web 版本,刚开始的时候的确不够流畅。有人说这跟代理工具和节点有关,通过更换工具和节点解决。\n解析异常\n一个 RSS 最核心的还是要能订阅并正常获取并解析订阅源的内容。这一点 Follow 给我的感觉不好。在订阅 袁凡 老师的博客,就出现了无法正常解析。\n\n同样的订阅,在 QiReader 上却表现很好。\n\n列表赚钱\n\n之前为什么水军这么多到处发订阅列表,今天用了下才知道原来 RSS 列表真的可以赚钱。第一次见到这种创新,和之前的饥饿营销绝配了。然而阅读器本身做得不怎样。\n\n很同意这个评论,对于这一种赚钱方式,的确第一次见到。\n其他看法\n在细节处理,希望这一款 Next-Gen Information Browser 继续打磨。', 'bodyHTML': '

在 2024 年国庆前后的这一段时间,Follow 的这个号称 Next-Gen Information Browser 的 RSS 阅读器在各大平台相当的火,各种疯抢激活码的帖子也是起此彼伏。直到 10 月 24,开始公测,上去体验了一下,发现也就跟其它 RSS 软件没啥太大区别,并没有说的那么玄乎。

\n\n

卡顿

\n

有人提到的公测遇到的第一个问题 "卡",加载缓慢。这个问题,我也感受到了,我一直用的 Web 版本,刚开始的时候的确不够流畅。有人说这跟代理工具和节点有关,通过更换工具和节点解决。

\n

解析异常

\n

一个 RSS 最核心的还是要能订阅并正常获取并解析订阅源的内容。这一点 Follow 给我的感觉不好。在订阅 袁凡 老师的博客,就出现了无法正常解析。
\nfollow-earfanfan

\n

同样的订阅,在 QiReader 上却表现很好。
\nqireader-earfanfan

\n

列表赚钱

\n
\n

之前为什么水军这么多到处发订阅列表,今天用了下才知道原来 RSS 列表真的可以赚钱。第一次见到这种创新,和之前的饥饿营销绝配了。然而阅读器本身做得不怎样。

\n
\n

很同意这个评论,对于这一种赚钱方式,的确第一次见到。

\n

其他看法

\n

在细节处理,希望这一款 Next-Gen Information Browser 继续打磨。

\n

follow-joe-hou

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'hisat2-build RAM 不足', 'number': 91, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/91', 'createdAt': '2024-10-23T07:39:36Z', 'lastEditedAt': None, 'updatedAt': '2024-10-23T07:39:37Z', 'body': '在 96G RAM 的节点跑 T2T-CHM13v2.0 的 HISAT2 index 时候,发现任务居然被系统 Killed 掉了。\r\n\r\n\r\n\r\n排查一下才发现是因为 RAM 内存不够! \r\n![hisat2-resource-usage-summary](https://kg.weiyan.cc/2024/10/hisat2-resource.png)\r\n\r\n> Note: If you use [--snp](https://open.bioqueue.org/home/knowledge/showKnowledge/sig/hisat2-build#--snp), [--ss](https://open.bioqueue.org/home/knowledge/showKnowledge/sig/hisat2-build#--ss), and/or [--exon](https://open.bioqueue.org/home/knowledge/showKnowledge/sig/hisat2-build#--exon), hisat2-build will need about **200 GB** RAM for the human genome size as index building involves a graph construction. Otherwise, you will be able to build an index on your desktop with 8GB RAM.\r\n> \r\n> From [hisat2-build manual with usage examples | BioQueue Encyclopedia](https://open.bioqueue.org/home/knowledge/showKnowledge/sig/hisat2-build)', 'bodyText': '在 96G RAM 的节点跑 T2T-CHM13v2.0 的 HISAT2 index 时候,发现任务居然被系统 Killed 掉了。\n\n排查一下才发现是因为 RAM 内存不够!\n\n\nNote: If you use --snp, --ss, and/or --exon, hisat2-build will need about 200 GB RAM for the human genome size as index building involves a graph construction. Otherwise, you will be able to build an index on your desktop with 8GB RAM.\nFrom hisat2-build manual with usage examples | BioQueue Encyclopedia', 'bodyHTML': '

在 96G RAM 的节点跑 T2T-CHM13v2.0 的 HISAT2 index 时候,发现任务居然被系统 Killed 掉了。

\n\n

排查一下才发现是因为 RAM 内存不够!
\nhisat2-resource-usage-summary

\n
\n

Note: If you use --snp, --ss, and/or --exon, hisat2-build will need about 200 GB RAM for the human genome size as index building involves a graph construction. Otherwise, you will be able to build an index on your desktop with 8GB RAM.

\n

From hisat2-build manual with usage examples | BioQueue Encyclopedia

\n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.1-生信'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'Galaxy 平台 release_24.x 升级之路', 'number': 90, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/90', 'createdAt': '2024-10-18T02:40:04Z', 'lastEditedAt': '2024-10-21T01:19:17Z', 'updatedAt': '2024-10-21T01:19:17Z', 'body': '记录一下 Galaxy 分析平台从 **release_20.09** 升级到 **release_24.0**,横跨九个发布版本的升级之路。\r\n\r\n\r\n\r\n## 为什么要升级\r\n\r\n很主要的一个原因是随着新技术的更新,旧版本的使用可能会存在一些安全隐患,尤其对于提供互联网公开访问的平台。新版本的升级有助于捕获并应用所有先前的安全更新,以确保平台的安全性。\r\n\r\n## 版本选择\r\n\r\n最开始选择的是 [release_24.1](https://docs.galaxyproject.org/en/master/releases/24.1_announce_user.html) 版本,但好不容易安装完成后才发现,这个新版本中增加了一个常规途径下无法隐藏的 **Activity Bar Interface**,一时间无法忍受。\r\n![23.1-activity-bar](https://kg.weiyan.cc/2024/10/23.1-activity-bar.png) \r\n![galaxy-24.1](https://kg.weiyan.cc/2024/10/galaxy-24.1.png)\r\n\r\n第二个原因是,后台 PostgreSQL 数据库的升级遇到了 [function gen_random_uuid() does not exist](https://help.galaxyproject.org/t/database-upgrade-error/13687) 异常,一下子没法解决也不想去升级 PostgreSQL 版本。\r\n\r\n所以,最终选择了从 **release_20.09** 升级到次新的 **release_24.0** 版本方案。\r\n\r\n## 安装系统环境\r\n\r\n这里以 release_24.1 作为示例,该环境要求同样适用于 release_24.0。\r\n\r\nGalaxy release_24.1 默认安装 node-v18.12.1,参考:`run.sh` → `./scripts/common_startup_functions.sh` → `./scripts/common_startup.sh` → `nodeenv -n "$NODE_VERSION" -p` 的安装代码。\r\n\r\nnode-v18.12.1 下载地址:\r\n\r\nnode-v18.12.1 要求 g++ 8.3.0 or clang++ 8.0.0: \r\n![node-v18.12.1-gcc](https://kg.weiyan.cc/2024/10/node-v18.12.1-gcc.webp)\r\n\r\n可以通过安装 Devtoolset 的方式解决: \r\n\r\n1. 手动调整 CentOS 7 的 SCL YUM 源(也可以 yum 安装),注意变更 `baseurl` 为阿里云或者其他的源链接。\r\n ```bash\r\n # 会默认在 /etc/yum.repos.d 下生成 2 个 repo 源文件\r\n # CentOS-SCLo-scl.repo\r\n # CentOS-SCLo-scl-rh.repo\r\n yum install centos-release-scl centos-release-scl-rh\r\n ```\r\n2. 更新 yum 源的缓存。\r\n ```bash\r\n cd /etc/yum.repos.d\r\n yum clean all\r\n yum makecache\r\n ```\r\n3. 安装 scl-utils,scl-utils 是管理 SCL (Software Collection) 环境设置和运行软件的一套软件工具。\r\n ```bash\r\n yum install scl-utils\r\n ```\r\n4. 安装 devtoolset-9。\r\n ```bash\r\n yum install devtoolset-9\r\n ```\r\n5. 激活 devtoolset-9。\r\n ```bash\r\n source /opt/rh/devtoolset-9/enable\r\n ```\r\n\r\n## Python 环境\r\n\r\nGalaxy 要求 Python >= 3.8,node-v18.12.1 要求 3.6<=Python<=3.10,这里选择 Python-3.9.18,安装如下。\r\n\r\n```bash\r\nwget https://www.python.org/ftp/python/3.9.18/Python-3.9.18.tgz\r\ntar zvxf Python-3.9.18.tgz\r\ncd Python-3.9.18\r\n$enabledevtoolset9\r\nexport TCLTK_LIBS="-L/home/shenweiyan/software/tcltK-8.5.19/lib -ltcl8.5 -ltk8.5"\r\nexport TCLTK_CFLAGS="-I/home/shenweiyan/software/tcltK-8.5.19/include"\r\n./configure --enable-optimizations --prefix=/home/shenweiyan/software/python-3.9.18 --with-openssl=/home/shenweiyan/software/openssl-1.1.1/ --with-tcltk-includes="-I/home/shenweiyan/software/tcltK-8.5.19/include" --with-tcltk-libs="-L/home/shenweiyan/software/tcltK-8.5.19/lib -ltcl8.5 -ltk8.5" \r\nmake -j 4\r\nmake install\r\n```\r\n\r\nPython-3.9.18 安装完成后,避免 `ssl` 模块无法正常 `import` 使用,需要在环境中增加以下设置。\r\n```bash\r\nexport LD_LIBRARY_PATH=/home/shenweiyan/software/openssl-1.1.1/lib:$LD_LIBRARY_PATH\r\n```\r\n\r\n## Node 环境\r\n\r\nGalaxy 的 `sh run.sh` 默认通过 `ssl` 的方式安装已经提前编译好的 node-v18.12.1-linux-x64.tar.gz(直接解压即可使用),对于系统版本比较低的服务器(如 CentOS 7)会存在 GLIBC 异常,因此需要调整为 `ignore_ssl_certs` 的下载方式 + source 源码安装的方式安装 node-v18.12.1。 \r\n![nodeenv--help](https://kg.weiyan.cc/2024/10/nodeenv-help.webp)\r\n\r\n所以,最终的方法为调整 `./scripts/common_startup.sh` 中 `nodeenv -n "$NODE_VERSION" -p` 的安装代码如下:\r\n```bash\r\nnodeenv -n "$NODE_VERSION" -p --source --ignore_ssl_certs --jobs=1\r\n```\r\n\r\nnode-v18.12.1 下载地址:。\r\n\r\n由于编译非常耗时(4核8G 的服务器编译了 1 个小时左右),且对 Python 版本有要求,建议手动安装,具体安装步骤如下。\r\n```bash\r\nshenweiyan@centos-vm-7 10:30:34 /home/shenweiyan/src/node-v18.12.1\r\n$ ./configure --prefix=/home/shenweiyan/software/node-v18.12.1\r\nNode.js configure: Found Python 3.11.6...\r\nPlease use python3.10 or python3.9 or python3.8 or python3.7 or python3.6.\r\n```\r\n\r\n```bash\r\n$ wget https://nodejs.org/download/release/v18.12.1/node-v18.12.1.tar.gz\r\n$ tar zvxf node-v18.12.1.tar.gz\r\n$ cd node-v18.12.1\r\n$ source /opt/rh/devtoolset-9/enable\r\n$ ./configure --prefix=/home/shenweiyan/software/node-v18.12.1\r\nNode.js configure: Found Python 3.9.18...\r\nINFO: configure completed successfully\r\n$ make -j 4\r\n$ make install\r\n```\r\n\r\n## Yarn 环境\r\n\r\n注意要先设置 `npm` 的路径,如果有多个版本的 `npm`,会因为版本混乱导致语法异常。\r\n\r\n```bash\r\nexport PATH=/home/shenweiyan/software/node-v18.12.1/bin:$PATH\r\n/home/shenweiyan/software/node-v18.12.1/bin/npm install --global yarn\r\n```\r\n\r\n## pip 源\r\n\r\nGalaxy 在安装 `requirements.txt` 的时候默认使用下面两个源:\r\n\r\n- \r\n- \r\n\r\n对于国内服务器,可以考虑更换为阿里云或者清华大学的 pip 源。可以:\r\n\r\n- 在 `scripts/common_startup.sh` 中修改:\r\n ```bash\r\n : ${PYPI_INDEX_URL:="https://mirrors.aliyun.com/pypi/simple/"}\r\n ```\r\n\r\n- 在 `requirements.txt` 头部增加:\r\n ```bash\r\n -i https://mirrors.aliyun.com/pypi/simple/\r\n --extra-index-url https://wheels.galaxyproject.org/simple\r\n ```\r\n\r\n## 数据库升级\r\n\r\n这是本次 Galaxy 核心版本升级时候遇到的最大问题。\r\n\r\n由于 Galaxy 在 release_21.05 新增加了一个 [`history_audit`](https://github.com/galaxyproject/galaxy/pull/11914) 数据表,release_20.09 的数据库直接执行 `sh manage_db.sh upgrade` 升级的时候 `history_audit` 数据表并不会一并创建和更新,因此最终导致在 Galaxy 服务启动的时候发生错误。\r\n\r\n这应该是数据库升级时候的一个bug,经过摸索发现,目前可以参考下面的文章,通过分步升级的方式解决。\r\n\r\n- \r\n\r\n以上解决方法,参考:[galaxyproject/galaxy #19016](https://github.com/galaxyproject/galaxy/issues/19016) \r\n \r\n![galaxy-issues-19016](https://kg.weiyan.cc/2024/10/galaxy-issues-19016.png)\r\n\r\n## 总结\r\n\r\n更新后的 release_24.0 界面看起来比旧版本要更加清爽舒服一些,各个页面的汉化功能也有所改善,新增的 Notifications 功能也挺不错,总之升级之后各个方面还是挺满意的,其他细节和功能还在体验中。\r\n', 'bodyText': '记录一下 Galaxy 分析平台从 release_20.09 升级到 release_24.0,横跨九个发布版本的升级之路。\n\n为什么要升级\n很主要的一个原因是随着新技术的更新,旧版本的使用可能会存在一些安全隐患,尤其对于提供互联网公开访问的平台。新版本的升级有助于捕获并应用所有先前的安全更新,以确保平台的安全性。\n版本选择\n最开始选择的是 release_24.1 版本,但好不容易安装完成后才发现,这个新版本中增加了一个常规途径下无法隐藏的 Activity Bar Interface,一时间无法忍受。\n\n\n第二个原因是,后台 PostgreSQL 数据库的升级遇到了 function gen_random_uuid() does not exist 异常,一下子没法解决也不想去升级 PostgreSQL 版本。\n所以,最终选择了从 release_20.09 升级到次新的 release_24.0 版本方案。\n安装系统环境\n这里以 release_24.1 作为示例,该环境要求同样适用于 release_24.0。\nGalaxy release_24.1 默认安装 node-v18.12.1,参考:run.sh → ./scripts/common_startup_functions.sh → ./scripts/common_startup.sh → nodeenv -n "$NODE_VERSION" -p 的安装代码。\nnode-v18.12.1 下载地址:https://nodejs.org/download/release/v18.12.1/\nnode-v18.12.1 要求 g++ 8.3.0 or clang++ 8.0.0:\n\n可以通过安装 Devtoolset 的方式解决:\n\n手动调整 CentOS 7 的 SCL YUM 源(也可以 yum 安装),注意变更 baseurl 为阿里云或者其他的源链接。\n# 会默认在 /etc/yum.repos.d 下生成 2 个 repo 源文件\n# CentOS-SCLo-scl.repo\n# CentOS-SCLo-scl-rh.repo\nyum install centos-release-scl centos-release-scl-rh\n\n更新 yum 源的缓存。\ncd /etc/yum.repos.d\nyum clean all\nyum makecache\n\n安装 scl-utils,scl-utils 是管理 SCL (Software Collection) 环境设置和运行软件的一套软件工具。\nyum install scl-utils\n\n安装 devtoolset-9。\nyum install devtoolset-9\n\n激活 devtoolset-9。\nsource /opt/rh/devtoolset-9/enable\n\n\nPython 环境\nGalaxy 要求 Python >= 3.8,node-v18.12.1 要求 3.6<=Python<=3.10,这里选择 Python-3.9.18,安装如下。\nwget https://www.python.org/ftp/python/3.9.18/Python-3.9.18.tgz\ntar zvxf Python-3.9.18.tgz\ncd Python-3.9.18\n$enabledevtoolset9\nexport TCLTK_LIBS="-L/home/shenweiyan/software/tcltK-8.5.19/lib -ltcl8.5 -ltk8.5"\nexport TCLTK_CFLAGS="-I/home/shenweiyan/software/tcltK-8.5.19/include"\n./configure --enable-optimizations --prefix=/home/shenweiyan/software/python-3.9.18 --with-openssl=/home/shenweiyan/software/openssl-1.1.1/ --with-tcltk-includes="-I/home/shenweiyan/software/tcltK-8.5.19/include" --with-tcltk-libs="-L/home/shenweiyan/software/tcltK-8.5.19/lib -ltcl8.5 -ltk8.5" \nmake -j 4\nmake install\nPython-3.9.18 安装完成后,避免 ssl 模块无法正常 import 使用,需要在环境中增加以下设置。\nexport LD_LIBRARY_PATH=/home/shenweiyan/software/openssl-1.1.1/lib:$LD_LIBRARY_PATH\nNode 环境\nGalaxy 的 sh run.sh 默认通过 ssl 的方式安装已经提前编译好的 node-v18.12.1-linux-x64.tar.gz(直接解压即可使用),对于系统版本比较低的服务器(如 CentOS 7)会存在 GLIBC 异常,因此需要调整为 ignore_ssl_certs 的下载方式 + source 源码安装的方式安装 node-v18.12.1。\n\n所以,最终的方法为调整 ./scripts/common_startup.sh 中 nodeenv -n "$NODE_VERSION" -p 的安装代码如下:\nnodeenv -n "$NODE_VERSION" -p --source --ignore_ssl_certs --jobs=1\nnode-v18.12.1 下载地址:https://nodejs.org/download/release/v18.12.1/。\n由于编译非常耗时(4核8G 的服务器编译了 1 个小时左右),且对 Python 版本有要求,建议手动安装,具体安装步骤如下。\nshenweiyan@centos-vm-7 10:30:34 /home/shenweiyan/src/node-v18.12.1\n$ ./configure --prefix=/home/shenweiyan/software/node-v18.12.1\nNode.js configure: Found Python 3.11.6...\nPlease use python3.10 or python3.9 or python3.8 or python3.7 or python3.6.\n$ wget https://nodejs.org/download/release/v18.12.1/node-v18.12.1.tar.gz\n$ tar zvxf node-v18.12.1.tar.gz\n$ cd node-v18.12.1\n$ source /opt/rh/devtoolset-9/enable\n$ ./configure --prefix=/home/shenweiyan/software/node-v18.12.1\nNode.js configure: Found Python 3.9.18...\nINFO: configure completed successfully\n$ make -j 4\n$ make install\nYarn 环境\n注意要先设置 npm 的路径,如果有多个版本的 npm,会因为版本混乱导致语法异常。\nexport PATH=/home/shenweiyan/software/node-v18.12.1/bin:$PATH\n/home/shenweiyan/software/node-v18.12.1/bin/npm install --global yarn\npip 源\nGalaxy 在安装 requirements.txt 的时候默认使用下面两个源:\n\nhttps://wheels.galaxyproject.org/simple\nhttps://pypi.python.org/simple\n\n对于国内服务器,可以考虑更换为阿里云或者清华大学的 pip 源。可以:\n\n\n在 scripts/common_startup.sh 中修改:\n: ${PYPI_INDEX_URL:="https://mirrors.aliyun.com/pypi/simple/"}\n\n\n在 requirements.txt 头部增加:\n-i https://mirrors.aliyun.com/pypi/simple/\n--extra-index-url https://wheels.galaxyproject.org/simple\n\n\n数据库升级\n这是本次 Galaxy 核心版本升级时候遇到的最大问题。\n由于 Galaxy 在 release_21.05 新增加了一个 history_audit 数据表,release_20.09 的数据库直接执行 sh manage_db.sh upgrade 升级的时候 history_audit 数据表并不会一并创建和更新,因此最终导致在 Galaxy 服务启动的时候发生错误。\n这应该是数据库升级时候的一个bug,经过摸索发现,目前可以参考下面的文章,通过分步升级的方式解决。\n\nhttps://mp.weixin.qq.com/s/arRZ-3mMrpUIsXYuqg4sGQ\n\n以上解决方法,参考:galaxyproject/galaxy #19016\n\n总结\n更新后的 release_24.0 界面看起来比旧版本要更加清爽舒服一些,各个页面的汉化功能也有所改善,新增的 Notifications 功能也挺不错,总之升级之后各个方面还是挺满意的,其他细节和功能还在体验中。', 'bodyHTML': '

记录一下 Galaxy 分析平台从 release_20.09 升级到 release_24.0,横跨九个发布版本的升级之路。

\n\n

为什么要升级

\n

很主要的一个原因是随着新技术的更新,旧版本的使用可能会存在一些安全隐患,尤其对于提供互联网公开访问的平台。新版本的升级有助于捕获并应用所有先前的安全更新,以确保平台的安全性。

\n

版本选择

\n

最开始选择的是 release_24.1 版本,但好不容易安装完成后才发现,这个新版本中增加了一个常规途径下无法隐藏的 Activity Bar Interface,一时间无法忍受。
\n23.1-activity-bar
\ngalaxy-24.1

\n

第二个原因是,后台 PostgreSQL 数据库的升级遇到了 function gen_random_uuid() does not exist 异常,一下子没法解决也不想去升级 PostgreSQL 版本。

\n

所以,最终选择了从 release_20.09 升级到次新的 release_24.0 版本方案。

\n

安装系统环境

\n

这里以 release_24.1 作为示例,该环境要求同样适用于 release_24.0。

\n

Galaxy release_24.1 默认安装 node-v18.12.1,参考:run.sh./scripts/common_startup_functions.sh./scripts/common_startup.shnodeenv -n "$NODE_VERSION" -p 的安装代码。

\n

node-v18.12.1 下载地址:https://nodejs.org/download/release/v18.12.1/

\n

node-v18.12.1 要求 g++ 8.3.0 or clang++ 8.0.0:
\nnode-v18.12.1-gcc

\n

可以通过安装 Devtoolset 的方式解决:

\n
    \n
  1. 手动调整 CentOS 7 的 SCL YUM 源(也可以 yum 安装),注意变更 baseurl 为阿里云或者其他的源链接。\n
    # 会默认在 /etc/yum.repos.d 下生成 2 个 repo 源文件\n# CentOS-SCLo-scl.repo\n# CentOS-SCLo-scl-rh.repo\nyum install centos-release-scl centos-release-scl-rh
    \n
  2. \n
  3. 更新 yum 源的缓存。\n
    cd /etc/yum.repos.d\nyum clean all\nyum makecache
    \n
  4. \n
  5. 安装 scl-utils,scl-utils 是管理 SCL (Software Collection) 环境设置和运行软件的一套软件工具。\n
    yum install scl-utils
    \n
  6. \n
  7. 安装 devtoolset-9。\n
    yum install devtoolset-9
    \n
  8. \n
  9. 激活 devtoolset-9。\n
    source /opt/rh/devtoolset-9/enable
    \n
  10. \n
\n

Python 环境

\n

Galaxy 要求 Python >= 3.8,node-v18.12.1 要求 3.6<=Python<=3.10,这里选择 Python-3.9.18,安装如下。

\n
wget https://www.python.org/ftp/python/3.9.18/Python-3.9.18.tgz\ntar zvxf Python-3.9.18.tgz\ncd Python-3.9.18\n$enabledevtoolset9\nexport TCLTK_LIBS="-L/home/shenweiyan/software/tcltK-8.5.19/lib -ltcl8.5 -ltk8.5"\nexport TCLTK_CFLAGS="-I/home/shenweiyan/software/tcltK-8.5.19/include"\n./configure --enable-optimizations --prefix=/home/shenweiyan/software/python-3.9.18 --with-openssl=/home/shenweiyan/software/openssl-1.1.1/ --with-tcltk-includes="-I/home/shenweiyan/software/tcltK-8.5.19/include" --with-tcltk-libs="-L/home/shenweiyan/software/tcltK-8.5.19/lib -ltcl8.5 -ltk8.5" \nmake -j 4\nmake install
\n

Python-3.9.18 安装完成后,避免 ssl 模块无法正常 import 使用,需要在环境中增加以下设置。

\n
export LD_LIBRARY_PATH=/home/shenweiyan/software/openssl-1.1.1/lib:$LD_LIBRARY_PATH
\n

Node 环境

\n

Galaxy 的 sh run.sh 默认通过 ssl 的方式安装已经提前编译好的 node-v18.12.1-linux-x64.tar.gz(直接解压即可使用),对于系统版本比较低的服务器(如 CentOS 7)会存在 GLIBC 异常,因此需要调整为 ignore_ssl_certs 的下载方式 + source 源码安装的方式安装 node-v18.12.1。
\nnodeenv--help

\n

所以,最终的方法为调整 ./scripts/common_startup.shnodeenv -n "$NODE_VERSION" -p 的安装代码如下:

\n
nodeenv -n "$NODE_VERSION" -p --source --ignore_ssl_certs --jobs=1
\n

node-v18.12.1 下载地址:https://nodejs.org/download/release/v18.12.1/

\n

由于编译非常耗时(4核8G 的服务器编译了 1 个小时左右),且对 Python 版本有要求,建议手动安装,具体安装步骤如下。

\n
shenweiyan@centos-vm-7 10:30:34 /home/shenweiyan/src/node-v18.12.1\n$ ./configure --prefix=/home/shenweiyan/software/node-v18.12.1\nNode.js configure: Found Python 3.11.6...\nPlease use python3.10 or python3.9 or python3.8 or python3.7 or python3.6.
\n
$ wget https://nodejs.org/download/release/v18.12.1/node-v18.12.1.tar.gz\n$ tar zvxf node-v18.12.1.tar.gz\n$ cd node-v18.12.1\n$ source /opt/rh/devtoolset-9/enable\n$ ./configure --prefix=/home/shenweiyan/software/node-v18.12.1\nNode.js configure: Found Python 3.9.18...\nINFO: configure completed successfully\n$ make -j 4\n$ make install
\n

Yarn 环境

\n

注意要先设置 npm 的路径,如果有多个版本的 npm,会因为版本混乱导致语法异常。

\n
export PATH=/home/shenweiyan/software/node-v18.12.1/bin:$PATH\n/home/shenweiyan/software/node-v18.12.1/bin/npm install --global yarn
\n

pip 源

\n

Galaxy 在安装 requirements.txt 的时候默认使用下面两个源:

\n\n

对于国内服务器,可以考虑更换为阿里云或者清华大学的 pip 源。可以:

\n
    \n
  • \n

    scripts/common_startup.sh 中修改:

    \n
    : ${PYPI_INDEX_URL:="https://mirrors.aliyun.com/pypi/simple/"}
    \n
  • \n
  • \n

    requirements.txt 头部增加:

    \n
    -i https://mirrors.aliyun.com/pypi/simple/\n--extra-index-url https://wheels.galaxyproject.org/simple
    \n
  • \n
\n

数据库升级

\n

这是本次 Galaxy 核心版本升级时候遇到的最大问题。

\n

由于 Galaxy 在 release_21.05 新增加了一个 history_audit 数据表,release_20.09 的数据库直接执行 sh manage_db.sh upgrade 升级的时候 history_audit 数据表并不会一并创建和更新,因此最终导致在 Galaxy 服务启动的时候发生错误。

\n

这应该是数据库升级时候的一个bug,经过摸索发现,目前可以参考下面的文章,通过分步升级的方式解决。

\n\n

以上解决方法,参考:galaxyproject/galaxy #19016

\n

galaxy-issues-19016

\n

总结

\n

更新后的 release_24.0 界面看起来比旧版本要更加清爽舒服一些,各个页面的汉化功能也有所改善,新增的 Notifications 功能也挺不错,总之升级之后各个方面还是挺满意的,其他细节和功能还在体验中。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '3.1-Galaxy'}, 'labels': {'nodes': [{'name': '3.1.x-GalaxyOther'}]}, 'comments': {'nodes': []}}, {'title': '上下班听广播', 'number': 89, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/89', 'createdAt': '2024-09-29T06:11:30Z', 'lastEditedAt': '2024-09-29T06:33:13Z', 'updatedAt': '2024-09-29T07:09:40Z', 'body': '自从切换了电动车的通勤方式,同时就打开了广播的大门。\r\n\r\n\r\n\r\n![hello-morning](https://kg.weiyan.cc/2024/09/hello-morning.webp)\r\n\r\n符合自己兴趣的电台不好找,尤其是下午下班的这段时间。\r\n\r\n## 珠江第一线\r\n\r\n珠江第一线,朝朝陪你饮早茶!\r\n\r\n早上的选择中个人尤其喜欢珠江经济台的《珠江第一线》,它的播出时间是周一到周五的 07:30-09:00,是珠江经济台重点打造的一档粤语民生新闻名牌节目,李嘉、淼钧、郑达等一众名嘴的组合,加上独具的广府文化韵味,针砭时弊,作风硬朗,嬉笑怒骂,亦庄亦谐,让人在上班的路上更加放松。\r\n\r\n> 《珠江第一线》开播之时,就在广东广播界率先提出“打造听众上班路上的新闻资讯大餐”的口号。节目立足民生视觉,着重在内容碎片化上下功夫,让海量资讯更有层次感,更适合伴随性收听的人群;另外增加生活化话题、软性资讯,讲老百姓身边的故事,塑造老百姓“贴心老友”节目品牌形象;同时强化新闻时评的针对性,聘请最强广播评论专家团队,与市民评论员联袂,每天对社会热点话题进行精辟点评;节目主持人也一改传统的新闻节目播报方式,使用个性化的“说新闻”,节目过程还不时插播上班路上的交通、天气状况,使节目更接地气,更具亲和力。\r\n\r\n## 放工路上\r\n\r\n下班时间段的选择,要说十分喜欢的节目目前没找到,虽然会听同样是珠江经济台的《珠江晚高峰》,但找不到《珠江第一线》的舒适感。\r\n', 'bodyText': '自从切换了电动车的通勤方式,同时就打开了广播的大门。\n\n\n符合自己兴趣的电台不好找,尤其是下午下班的这段时间。\n珠江第一线\n珠江第一线,朝朝陪你饮早茶!\n早上的选择中个人尤其喜欢珠江经济台的《珠江第一线》,它的播出时间是周一到周五的 07:30-09:00,是珠江经济台重点打造的一档粤语民生新闻名牌节目,李嘉、淼钧、郑达等一众名嘴的组合,加上独具的广府文化韵味,针砭时弊,作风硬朗,嬉笑怒骂,亦庄亦谐,让人在上班的路上更加放松。\n\n《珠江第一线》开播之时,就在广东广播界率先提出“打造听众上班路上的新闻资讯大餐”的口号。节目立足民生视觉,着重在内容碎片化上下功夫,让海量资讯更有层次感,更适合伴随性收听的人群;另外增加生活化话题、软性资讯,讲老百姓身边的故事,塑造老百姓“贴心老友”节目品牌形象;同时强化新闻时评的针对性,聘请最强广播评论专家团队,与市民评论员联袂,每天对社会热点话题进行精辟点评;节目主持人也一改传统的新闻节目播报方式,使用个性化的“说新闻”,节目过程还不时插播上班路上的交通、天气状况,使节目更接地气,更具亲和力。\n\n放工路上\n下班时间段的选择,要说十分喜欢的节目目前没找到,虽然会听同样是珠江经济台的《珠江晚高峰》,但找不到《珠江第一线》的舒适感。', 'bodyHTML': '

自从切换了电动车的通勤方式,同时就打开了广播的大门。

\n\n

hello-morning

\n

符合自己兴趣的电台不好找,尤其是下午下班的这段时间。

\n

珠江第一线

\n

珠江第一线,朝朝陪你饮早茶!

\n

早上的选择中个人尤其喜欢珠江经济台的《珠江第一线》,它的播出时间是周一到周五的 07:30-09:00,是珠江经济台重点打造的一档粤语民生新闻名牌节目,李嘉、淼钧、郑达等一众名嘴的组合,加上独具的广府文化韵味,针砭时弊,作风硬朗,嬉笑怒骂,亦庄亦谐,让人在上班的路上更加放松。

\n
\n

《珠江第一线》开播之时,就在广东广播界率先提出“打造听众上班路上的新闻资讯大餐”的口号。节目立足民生视觉,着重在内容碎片化上下功夫,让海量资讯更有层次感,更适合伴随性收听的人群;另外增加生活化话题、软性资讯,讲老百姓身边的故事,塑造老百姓“贴心老友”节目品牌形象;同时强化新闻时评的针对性,聘请最强广播评论专家团队,与市民评论员联袂,每天对社会热点话题进行精辟点评;节目主持人也一改传统的新闻节目播报方式,使用个性化的“说新闻”,节目过程还不时插播上班路上的交通、天气状况,使节目更接地气,更具亲和力。

\n
\n

放工路上

\n

下班时间段的选择,要说十分喜欢的节目目前没找到,虽然会听同样是珠江经济台的《珠江晚高峰》,但找不到《珠江第一线》的舒适感。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'All in one', 'number': 88, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/88', 'createdAt': '2024-09-24T07:36:36Z', 'lastEditedAt': None, 'updatedAt': '2024-09-24T07:36:37Z', 'body': '写笔记,做表格的很多时候,总有一个 All in one 的魔咒在脑海挥之不去,以前用语雀就想当然 All in yuque,后来又想着 All in GitHub,但现实终究是现实。\r\n\r\n\r\n\r\n没有十全十美的平台,语雀就没有邮箱、日历之类的功能;小记也没有浮墨笔记那么好用。\r\n\r\nGitHub 虽好,但始终有一堵长城横亘在前面,时时刻刻提醒着你小心翼翼。\r\n\r\n现在的飞书,各种功能都很齐全,但是不能实时查看文档的 Markdown,自己也没有能力去造这样一个轮子。有很多的时候,都有一个 All in feishu 的魔咒的诱惑着我,但又一次一次被它的木桶理论劝退。\r\n\r\n知识的沉淀,对于承受的载体没有什么是可以从一而终一成不变的,很多东西虽然分散,但也印证了不要把所有的鸡蛋放进一个篮子。逐渐的,我用上了飞书国际版的邮箱,我用上了语雀(小记/知识库)来记录我的一些碎片想法和文字,最终还是选择 GitHub 来记录这一切。\r\n\r\n不得不说,GitHub 真是个码字的好地方。', 'bodyText': '写笔记,做表格的很多时候,总有一个 All in one 的魔咒在脑海挥之不去,以前用语雀就想当然 All in yuque,后来又想着 All in GitHub,但现实终究是现实。\n\n没有十全十美的平台,语雀就没有邮箱、日历之类的功能;小记也没有浮墨笔记那么好用。\nGitHub 虽好,但始终有一堵长城横亘在前面,时时刻刻提醒着你小心翼翼。\n现在的飞书,各种功能都很齐全,但是不能实时查看文档的 Markdown,自己也没有能力去造这样一个轮子。有很多的时候,都有一个 All in feishu 的魔咒的诱惑着我,但又一次一次被它的木桶理论劝退。\n知识的沉淀,对于承受的载体没有什么是可以从一而终一成不变的,很多东西虽然分散,但也印证了不要把所有的鸡蛋放进一个篮子。逐渐的,我用上了飞书国际版的邮箱,我用上了语雀(小记/知识库)来记录我的一些碎片想法和文字,最终还是选择 GitHub 来记录这一切。\n不得不说,GitHub 真是个码字的好地方。', 'bodyHTML': '

写笔记,做表格的很多时候,总有一个 All in one 的魔咒在脑海挥之不去,以前用语雀就想当然 All in yuque,后来又想着 All in GitHub,但现实终究是现实。

\n\n

没有十全十美的平台,语雀就没有邮箱、日历之类的功能;小记也没有浮墨笔记那么好用。

\n

GitHub 虽好,但始终有一堵长城横亘在前面,时时刻刻提醒着你小心翼翼。

\n

现在的飞书,各种功能都很齐全,但是不能实时查看文档的 Markdown,自己也没有能力去造这样一个轮子。有很多的时候,都有一个 All in feishu 的魔咒的诱惑着我,但又一次一次被它的木桶理论劝退。

\n

知识的沉淀,对于承受的载体没有什么是可以从一而终一成不变的,很多东西虽然分散,但也印证了不要把所有的鸡蛋放进一个篮子。逐渐的,我用上了飞书国际版的邮箱,我用上了语雀(小记/知识库)来记录我的一些碎片想法和文字,最终还是选择 GitHub 来记录这一切。

\n

不得不说,GitHub 真是个码字的好地方。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'GCC 版本不一致导致的 R magick 包安装错误', 'number': 87, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/87', 'createdAt': '2024-09-10T05:43:01Z', 'lastEditedAt': '2024-09-11T03:00:33Z', 'updatedAt': '2024-09-11T03:00:33Z', 'body': '在安装 Y 叔的 `yyplot` 时候,发现 `magick` 依赖包安装的时候的一些棘手问题,特此记录一下。\r\n\r\n\r\n\r\n## R-4.0.3 安装\r\n\r\n```r\r\n> library(remotes)\r\n> remotes::install_github("GuangchuangYu/yyplot")\r\n...\r\n* installing *source* package ‘magick’ ...\r\n** package ‘magick’ successfully unpacked and MD5 sums checked\r\n** using staged installation\r\nPackage Magick++ was not found in the pkg-config search path.\r\nPerhaps you should add the directory containing `Magick++.pc\'\r\nto the PKG_CONFIG_PATH environment variable\r\nNo package \'Magick++\' found\r\nUsing PKG_CFLAGS=\r\nUsing PKG_LIBS=-lMagick++-6.Q16 -lMagickWand-6.Q16 -lMagickCore-6.Q16\r\n--------------------------- [ANTICONF] --------------------------------\r\nConfiguration failed to find the Magick++ library. Try installing:\r\n - deb: libmagick++-dev (Debian, Ubuntu)\r\n - rpm: ImageMagick-c++-devel (Fedora, CentOS, RHEL)\r\n - brew: imagemagick or imagemagick@6 (MacOS)\r\nIf Magick++ is already installed, check that \'pkg-config\' is in your\r\nPATH and PKG_CONFIG_PATH contains a Magick++.pc file. If pkg-config\r\nis unavailable you can set INCLUDE_DIR and LIB_DIR manually via:\r\nR CMD INSTALL --configure-vars=\'INCLUDE_DIR=... LIB_DIR=...\'\r\n-------------------------- [ERROR MESSAGE] ---------------------------\r\n:1:22: fatal error: Magick++.h: No such file or directory\r\ncompilation terminated.\r\n--------------------------------------------------------------------\r\nERROR: configuration failed for package ‘magick’\r\n* removing ‘/home/shenweiyan/software/R/R-4.0.3/lib64/R/library/magick’\r\nError: Failed to install \'yyplot\' from GitHub:\r\n (converted from warning) installation of package ‘magick’ had non-zero exit status\r\n> quit()\r\nSave workspace image? [y/n/c]: n\r\n```\r\n\r\n仅在 Bash 环境配置了 `PATH` 和 `PKG_CONFIG_PATH` 是不够的,安装过程会提示动态库的问题。 \r\n```\r\n# export PATH=/home/shenweiyan/software/ImageMagick-7.0.10/bin:$PATH\r\n# export PKG_CONFIG_PATH=/home/shenweiyan/software/ImageMagick-7.0.10/lib/pkgconfig:$PKG_CONFIG_PATH\r\n```\r\n\r\n```r\r\n> library(remotes)\r\n> remotes::install_github("GuangchuangYu/yyplot")\r\n...\r\n** R\r\n** inst\r\n** byte-compile and prepare package for lazy loading\r\n** help\r\n*** installing help indices\r\n** building package indices\r\n** installing vignettes\r\n** testing if installed package can be loaded from temporary location\r\nError: package or namespace load failed for ‘magick’ in dyn.load(file, DLLpath = DLLpath, ...):\r\n unable to load shared object \'/home/shenweiyan/software/R/R-4.0.3/lib64/R/library/00LOCK-magick/00new/magick/libs/magick.so\':\r\n libMagick++-7.Q16HDRI.so.4: cannot open shared object file: No such file or directory\r\nError: loading failed\r\nExecution halted\r\nERROR: loading failed\r\n* removing ‘/home/shenweiyan/software/R/R-4.0.3/lib64/R/library/magick’\r\nError: Failed to install \'yyplot\' from GitHub:\r\n (converted from warning) installation of package ‘magick’ had non-zero exit status\r\n> quit()\r\nSave workspace image? [y/n/c]: n\r\n```\r\n最终解决方案:\r\n\r\n1. 手动安装 `ggimage_0.3.1`。\r\n```r\r\npkg <- \'http://cran.r-project.org/src/contrib/Archive/ggimage/ggimage_0.3.1.tar.gz\'\r\ninstall.packages(pkg, repos=NULL, type="source")\r\n```\r\n\r\n2. 配置必要环境。\r\n```bash\r\nexport PATH=/home/shenweiyan/software/ImageMagick-7.0.10/bin:$PATH\r\nexport PKG_CONFIG_PATH=/home/shenweiyan/software/ImageMagick-7.0.10/lib/pkgconfig:$PKG_CONFIG_PATH\r\nexport LD_LIBRARY_PATH=/home/shenweiyan/software/ImageMagick-7.0.10/lib:$LD_LIBRARY_PATH\r\n```\r\n\r\n3. 安装。根据提示,先安装缺失的 `meme` 包,然后再安装 `yyplot`。\r\n```r\r\n> library(remotes)\r\n> options("repos"=c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))\r\n> install.packages(\'meme\')\r\n> remotes::install_github("GuangchuangYu/yyplot")\r\n```\r\n\r\n## R-4.3.0 安装\r\n\r\nR-4.3.0 安装 `magick_2.8.4` 会出现 [ropensci/magick#166](https://github.com/ropensci/magick/issues/166) 的问题。根据 [ropensci/magick#166#issuecomment-457875591](https://github.com/ropensci/magick/issues/166#issuecomment-457875591) 的描述,**编译 ImageMagick 的 gcc 需要跟编译 R 的 gcc 保持版本一致**。\r\n\r\n1. 重新编译安装 ImageMagick\r\n```bash\r\nwget https://download.imagemagick.org/archive/releases/ImageMagick-7.0.10-24.tar.xz\r\nextract ImageMagick-7.0.10-24.tar.xz\r\ncd ImageMagick-7.0.10-24\r\n./configure CC=/home/shenweiyan/software/gcc-7.3.0/bin/gcc CXX=/home/shenweiyan/software/gcc-7.3.0/bin/g++ --prefix=/home/shenweiyan/software/ImageMagick-7.0.10-24\r\nmake \r\nmake install\r\n```\r\n\r\n2. 安装 `magick` 包\r\n```bash\r\n# export PATH=/home/shenweiyan/software/ImageMagick-7.0.10-24/bin:$PATH\r\n# export PKG_CONFIG_PATH=/home/shenweiyan/software/ImageMagick-7.0.10-24/lib/pkgconfig:$PKG_CONFIG_PATH\r\n# export LD_LIBRARY_PATH=/home/shenweiyan/software/ImageMagick-7.0.10-24/lib:$LD_LIBRARY_PATH\r\n/home/shenweiyan/software/R/R-4.3.0/bin/R\r\n> options("repos"=c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))\r\n> install.packages(\'magick\')\r\n...\r\n```\r\n\r\n3. 根据提示,先安装缺失的 `meme` 包,然后再安装 `yyplot`。\r\n```r\r\n> library(remotes)\r\n> options("repos"=c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))\r\n> install.packages(\'meme\')\r\n> remotes::install_github("GuangchuangYu/yyplot")\r\n```', 'bodyText': '在安装 Y 叔的 yyplot 时候,发现 magick 依赖包安装的时候的一些棘手问题,特此记录一下。\n\nR-4.0.3 安装\n> library(remotes)\n> remotes::install_github("GuangchuangYu/yyplot")\n...\n* installing *source* package ‘magick’ ...\n** package ‘magick’ successfully unpacked and MD5 sums checked\n** using staged installation\nPackage Magick++ was not found in the pkg-config search path.\nPerhaps you should add the directory containing `Magick++.pc\'\nto the PKG_CONFIG_PATH environment variable\nNo package \'Magick++\' found\nUsing PKG_CFLAGS=\nUsing PKG_LIBS=-lMagick++-6.Q16 -lMagickWand-6.Q16 -lMagickCore-6.Q16\n--------------------------- [ANTICONF] --------------------------------\nConfiguration failed to find the Magick++ library. Try installing:\n - deb: libmagick++-dev (Debian, Ubuntu)\n - rpm: ImageMagick-c++-devel (Fedora, CentOS, RHEL)\n - brew: imagemagick or imagemagick@6 (MacOS)\nIf Magick++ is already installed, check that \'pkg-config\' is in your\nPATH and PKG_CONFIG_PATH contains a Magick++.pc file. If pkg-config\nis unavailable you can set INCLUDE_DIR and LIB_DIR manually via:\nR CMD INSTALL --configure-vars=\'INCLUDE_DIR=... LIB_DIR=...\'\n-------------------------- [ERROR MESSAGE] ---------------------------\n:1:22: fatal error: Magick++.h: No such file or directory\ncompilation terminated.\n--------------------------------------------------------------------\nERROR: configuration failed for package ‘magick’\n* removing ‘/home/shenweiyan/software/R/R-4.0.3/lib64/R/library/magick’\nError: Failed to install \'yyplot\' from GitHub:\n (converted from warning) installation of package ‘magick’ had non-zero exit status\n> quit()\nSave workspace image? [y/n/c]: n\n仅在 Bash 环境配置了 PATH 和 PKG_CONFIG_PATH 是不够的,安装过程会提示动态库的问题。\n# export PATH=/home/shenweiyan/software/ImageMagick-7.0.10/bin:$PATH\n# export PKG_CONFIG_PATH=/home/shenweiyan/software/ImageMagick-7.0.10/lib/pkgconfig:$PKG_CONFIG_PATH\n\n> library(remotes)\n> remotes::install_github("GuangchuangYu/yyplot")\n...\n** R\n** inst\n** byte-compile and prepare package for lazy loading\n** help\n*** installing help indices\n** building package indices\n** installing vignettes\n** testing if installed package can be loaded from temporary location\nError: package or namespace load failed for ‘magick’ in dyn.load(file, DLLpath = DLLpath, ...):\n unable to load shared object \'/home/shenweiyan/software/R/R-4.0.3/lib64/R/library/00LOCK-magick/00new/magick/libs/magick.so\':\n libMagick++-7.Q16HDRI.so.4: cannot open shared object file: No such file or directory\nError: loading failed\nExecution halted\nERROR: loading failed\n* removing ‘/home/shenweiyan/software/R/R-4.0.3/lib64/R/library/magick’\nError: Failed to install \'yyplot\' from GitHub:\n (converted from warning) installation of package ‘magick’ had non-zero exit status\n> quit()\nSave workspace image? [y/n/c]: n\n最终解决方案:\n\n手动安装 ggimage_0.3.1。\n\npkg <- \'http://cran.r-project.org/src/contrib/Archive/ggimage/ggimage_0.3.1.tar.gz\'\ninstall.packages(pkg, repos=NULL, type="source")\n\n配置必要环境。\n\nexport PATH=/home/shenweiyan/software/ImageMagick-7.0.10/bin:$PATH\nexport PKG_CONFIG_PATH=/home/shenweiyan/software/ImageMagick-7.0.10/lib/pkgconfig:$PKG_CONFIG_PATH\nexport LD_LIBRARY_PATH=/home/shenweiyan/software/ImageMagick-7.0.10/lib:$LD_LIBRARY_PATH\n\n安装。根据提示,先安装缺失的 meme 包,然后再安装 yyplot。\n\n> library(remotes)\n> options("repos"=c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))\n> install.packages(\'meme\')\n> remotes::install_github("GuangchuangYu/yyplot")\nR-4.3.0 安装\nR-4.3.0 安装 magick_2.8.4 会出现 ropensci/magick#166 的问题。根据 ropensci/magick#166#issuecomment-457875591 的描述,编译 ImageMagick 的 gcc 需要跟编译 R 的 gcc 保持版本一致。\n\n重新编译安装 ImageMagick\n\nwget https://download.imagemagick.org/archive/releases/ImageMagick-7.0.10-24.tar.xz\nextract ImageMagick-7.0.10-24.tar.xz\ncd ImageMagick-7.0.10-24\n./configure CC=/home/shenweiyan/software/gcc-7.3.0/bin/gcc CXX=/home/shenweiyan/software/gcc-7.3.0/bin/g++ --prefix=/home/shenweiyan/software/ImageMagick-7.0.10-24\nmake \nmake install\n\n安装 magick 包\n\n# export PATH=/home/shenweiyan/software/ImageMagick-7.0.10-24/bin:$PATH\n# export PKG_CONFIG_PATH=/home/shenweiyan/software/ImageMagick-7.0.10-24/lib/pkgconfig:$PKG_CONFIG_PATH\n# export LD_LIBRARY_PATH=/home/shenweiyan/software/ImageMagick-7.0.10-24/lib:$LD_LIBRARY_PATH\n/home/shenweiyan/software/R/R-4.3.0/bin/R\n> options("repos"=c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))\n> install.packages(\'magick\')\n...\n\n根据提示,先安装缺失的 meme 包,然后再安装 yyplot。\n\n> library(remotes)\n> options("repos"=c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))\n> install.packages(\'meme\')\n> remotes::install_github("GuangchuangYu/yyplot")', 'bodyHTML': '

在安装 Y 叔的 yyplot 时候,发现 magick 依赖包安装的时候的一些棘手问题,特此记录一下。

\n\n

R-4.0.3 安装

\n
> library(remotes)\n> remotes::install_github("GuangchuangYu/yyplot")\n...\n* installing *source* packagemagick...\n** packagemagicksuccessfully unpacked and MD5 sums checked\n** using staged installation\nPackage Magick++ was not found in the pkg-config search path.\nPerhaps you should add the directory containing `Magick++.pc\'\nto the PKG_CONFIG_PATH environment variable\nNo package \'Magick++\' found\nUsing PKG_CFLAGS=\nUsing PKG_LIBS=-lMagick++-6.Q16 -lMagickWand-6.Q16 -lMagickCore-6.Q16\n--------------------------- [ANTICONF] --------------------------------\nConfiguration failed to find the Magick++ library. Try installing:\n - deb: libmagick++-dev (Debian, Ubuntu)\n - rpm: ImageMagick-c++-devel (Fedora, CentOS, RHEL)\n - brew: imagemagick or imagemagick@6 (MacOS)\nIf Magick++ is already installed, check that \'pkg-config\' is in your\nPATH and PKG_CONFIG_PATH contains a Magick++.pc file. If pkg-config\nis unavailable you can set INCLUDE_DIR and LIB_DIR manually via:\nR CMD INSTALL --configure-vars=\'INCLUDE_DIR=... LIB_DIR=...\'\n-------------------------- [ERROR MESSAGE] ---------------------------\n<stdin>:1:22: fatal error: Magick++.h: No such file or directory\ncompilation terminated.\n--------------------------------------------------------------------\nERROR: configuration failed for package ‘magick’\n* removing ‘/home/shenweiyan/software/R/R-4.0.3/lib64/R/library/magick’\nError: Failed to install \'yyplot\' from GitHub:\n  (converted from warning) installation of package ‘magick’ had non-zero exit status\n> quit()\nSave workspace image? [y/n/c]: n
\n

仅在 Bash 环境配置了 PATHPKG_CONFIG_PATH 是不够的,安装过程会提示动态库的问题。

\n
# export PATH=/home/shenweiyan/software/ImageMagick-7.0.10/bin:$PATH\n# export PKG_CONFIG_PATH=/home/shenweiyan/software/ImageMagick-7.0.10/lib/pkgconfig:$PKG_CONFIG_PATH\n
\n
> library(remotes)\n> remotes::install_github("GuangchuangYu/yyplot")\n...\n** R\n** inst\n** byte-compile and prepare package for lazy loading\n** help\n*** installing help indices\n** building package indices\n** installing vignettes\n** testing if installed package can be loaded from temporary location\nError: package or namespace load failed formagickin dyn.load(file, DLLpath = DLLpath, ...):\n unable to load shared object \'/home/shenweiyan/software/R/R-4.0.3/lib64/R/library/00LOCK-magick/00new/magick/libs/magick.so\':\n  libMagick++-7.Q16HDRI.so.4: cannot open shared object file: No such file or directory\nError: loading failed\nExecution halted\nERROR: loading failed\n* removing/home/shenweiyan/software/R/R-4.0.3/lib64/R/library/magick’\nError: Failed to install \'yyplot\' from GitHub:\n  (converted from warning) installation of packagemagickhad non-zero exit status\n> quit()\nSave workspace image? [y/n/c]: n
\n

最终解决方案:

\n
    \n
  1. 手动安装 ggimage_0.3.1
  2. \n
\n
pkg <- \'http://cran.r-project.org/src/contrib/Archive/ggimage/ggimage_0.3.1.tar.gz\'\ninstall.packages(pkg, repos=NULL, type="source")
\n
    \n
  1. 配置必要环境。
  2. \n
\n
export PATH=/home/shenweiyan/software/ImageMagick-7.0.10/bin:$PATH\nexport PKG_CONFIG_PATH=/home/shenweiyan/software/ImageMagick-7.0.10/lib/pkgconfig:$PKG_CONFIG_PATH\nexport LD_LIBRARY_PATH=/home/shenweiyan/software/ImageMagick-7.0.10/lib:$LD_LIBRARY_PATH
\n
    \n
  1. 安装。根据提示,先安装缺失的 meme 包,然后再安装 yyplot
  2. \n
\n
> library(remotes)\n> options("repos"=c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))\n> install.packages(\'meme\')\n> remotes::install_github("GuangchuangYu/yyplot")
\n

R-4.3.0 安装

\n

R-4.3.0 安装 magick_2.8.4 会出现 ropensci/magick#166 的问题。根据 ropensci/magick#166#issuecomment-457875591 的描述,编译 ImageMagick 的 gcc 需要跟编译 R 的 gcc 保持版本一致

\n
    \n
  1. 重新编译安装 ImageMagick
  2. \n
\n
wget https://download.imagemagick.org/archive/releases/ImageMagick-7.0.10-24.tar.xz\nextract ImageMagick-7.0.10-24.tar.xz\ncd ImageMagick-7.0.10-24\n./configure CC=/home/shenweiyan/software/gcc-7.3.0/bin/gcc CXX=/home/shenweiyan/software/gcc-7.3.0/bin/g++ --prefix=/home/shenweiyan/software/ImageMagick-7.0.10-24\nmake \nmake install
\n
    \n
  1. 安装 magick
  2. \n
\n
# export PATH=/home/shenweiyan/software/ImageMagick-7.0.10-24/bin:$PATH\n# export PKG_CONFIG_PATH=/home/shenweiyan/software/ImageMagick-7.0.10-24/lib/pkgconfig:$PKG_CONFIG_PATH\n# export LD_LIBRARY_PATH=/home/shenweiyan/software/ImageMagick-7.0.10-24/lib:$LD_LIBRARY_PATH\n/home/shenweiyan/software/R/R-4.3.0/bin/R\n> options("repos"=c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))\n> install.packages(\'magick\')\n...
\n
    \n
  1. 根据提示,先安装缺失的 meme 包,然后再安装 yyplot
  2. \n
\n
> library(remotes)\n> options("repos"=c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))\n> install.packages(\'meme\')\n> remotes::install_github("GuangchuangYu/yyplot")
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '1.3.6-R'}]}, 'comments': {'nodes': []}}, {'title': 'Linux 下 PostgreSQL 源码编译安装', 'number': 86, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/86', 'createdAt': '2024-09-03T02:03:58Z', 'lastEditedAt': '2024-09-04T01:00:39Z', 'updatedAt': '2024-09-04T01:00:39Z', 'body': 'PostgreSQL 是一个功能强大的开源对象关系数据库管理系统(ORDBMS),它从伯克利写的 POSTGRES 软件包发展而来(1995 年几个 UCB 的学生为 Post-Ingres 开发了 SQL 的接口,正式发布了 PostgreSQL95,随后一步步在开源社区中成长起来),经过十几年的发展, PostgreSQL 已经成为世界上发展最快最受欢迎的数据库系统之一。\r\n\r\n本文章主要介绍在 CentOS 下源码编码安装 PostgreSQL-10.0 的一些简单步骤,以供参考。\r\n\r\n\r\n\r\n## 1. 新增用户组及用户\r\n\r\nPostgreSQL 默认是通过 `postgres:postgres` 来启动和使用的,因此在安装 PostgreSQL 前需要先创建 `postgres` 用户组及 `postgres` 用户。\r\n\r\n```bash\r\n# 在root权限下进行\r\ngroupadd postgres # 添加postgres用户组\r\nuseradd postgres -g postgres # 添加postgres用户\r\npasswd postgres # 设置postgres用户密码\r\n```\r\n\r\n## 2. 安装\r\n\r\n```\r\n$ wget https://ftp.postgresql.org/pub/source/v10.0/postgresql-10.0.tar.gz\r\n$ tar zvxf postgresql-10.0.tar.gz\r\n$ cd postgresql-10.0\r\n$ ./configure --prefix=/data/softwares/pgsql\r\n$ make\r\n$ make install\r\n```\r\n\r\n解决依赖:\r\n\r\n```\r\nFAQ1:configure: error: readline library not found\r\n$ yum install readline-devel\r\n\r\nFAQ2:configure: error: zlib library not found\r\n$ yum install zlib-devel\r\n```\r\n\r\n## 3. 启动\r\n\r\n```\r\n# 新建数据库数据文件目录\r\n$ mkdir /data/softwares/pgsql/data\r\n \r\n# 新建数据库 log 文件目录\r\n$ mkdir /data/softwares/pgsql/log\r\n \r\n# 修改目录拥有者\r\n$ chown postgres:postgres /data/softwares/pgsql/data -R\r\n$ chown postgres:postgres /data/softwares/pgsql/log -R\r\n \r\n# 执行数据库初始化脚本\r\n$ su postgres\r\n$ /data/softwares/pgsql/bin/initdb --encoding=utf8 -D /data/softwares/pgsql/data\r\n \r\n# 启动 PostgreSQL 服务\r\n$ /data/softwares/pgsql/bin/pg_ctl -D /data/softwares/pgsql/data -l /data/softwares/pgsql/log/postgresql.log start #postgres 用户下执行\r\n \r\n# 登录 PostgreSQL 数据库\r\n$ psql\r\n```\r\n\r\n![psql-db-list](https://kg.weiyan.cc/2024/09/psql-db-list.webp)\r\n\r\n## 4. 重启\r\n\r\n```\r\n$ su postgres\r\n$ /data/softwares/pgsql/bin/pg_ctl -D /data/softwares/pgsql/data -l /data/softwares/pgsql/log/postgresql.log restart\r\n```\r\n\r\n## 5. 设置开机启动\r\n\r\n解压后的 postgresql-x.x.x 下提供了基于 freebsd、linux、osx 3 个系统的 `postgresql` 启动命令。\r\n\r\n**1)对于通过源码自定义安装的 pgsql,需要修改相关启动脚本:**\r\n\r\n```bash\r\n$ cd postgresql-10.0/postgresql-10.0/contrib/start-scripts\r\n$ vi linux\r\n......\r\n......\r\n# Installation prefix\r\nprefix=/data/softwares/pgsql\r\n \r\n# Data directory\r\nPGDATA="/data/softwares/pgsql/data"\r\n \r\n# Who to run the postmaster as, usually "postgres". (NOT "root")\r\nPGUSER=postgres\r\n \r\n# Where to keep a log file\r\nPGLOG="$PGDATA/serverlog"\r\n......\r\n......\r\n```\r\n\r\n**2)设置数据库开机启动:**\r\n\r\n```bash\r\n$ cp /data/softwares/source/postgresql-10.0/postgresql-10.0/contrib/start-scripts/linux /etc/init.d/postgresql\r\n\r\n# 添加执行权限\r\n$ chmod a+x /etc/init.d/postgresql\r\n\r\n# 添加至开机启动\r\n$ chkconfig --add postgresql\r\n$ chkconfig postgresql on\r\n```\r\n\r\n**3)查看 postgresql 状态**\r\n\r\n```bash\r\n$ service postgresql status\r\npg_ctl: server is running (PID: 32586)\r\n/data/softwares/pgsql/bin/postgres "-D" "/data/softwares/pgsql/data"\r\n```\r\n\r\n## 6. 禁止管理员空密码登录\r\n\r\n在 PostgreSQL 中,如果你想禁止管理员(通常是 `postgres` 用户)使用空密码登录(正常情况下 `postgres` 用户可以直接使用 `psql` 命令直接登录 PostgreSQL),你可以通过修改 `pg_hba.conf` 文件来实现。\r\n\r\n1. 找到你的 `pg_hba.conf` 文件。这个文件通常位于 PostgreSQL 的数据目录中,例如 `/var/lib/pgsql/data` 或 `/etc/postgresql//main`。\r\n\r\n2. 修改 `pg_hba.conf` 文件,将管理员的登录方式从 `trust` 更改为 `md5` 或 `password`。这意味着所有连接,包括 `postgres` 用户的,都需要提供密码。\r\n\r\n例如,将以下行:\r\n```\r\nlocal all postgres trust\r\n```\r\n\r\n修改为:\r\n```\r\nlocal all postgres md5\r\n```\r\n\r\n3. 重新加载或重启 PostgreSQL 服务以应用更改。\r\n\r\n重新加载配置的命令通常是:\r\n```bash\r\npg_ctl reload\r\n```\r\n\r\n或者重启服务:\r\n```bash\r\nsystemctl restart postgresql\r\n```\r\n\r\n或者在不同的系统中可能是:\r\n```bash\r\nservice postgresql restart\r\n```\r\n\r\n完成这些步骤后,`postgres` 用户将不能再使用空密码登录数据库。其他用户如果想登录数据库,也需要提供密码。\r\n', 'bodyText': 'PostgreSQL 是一个功能强大的开源对象关系数据库管理系统(ORDBMS),它从伯克利写的 POSTGRES 软件包发展而来(1995 年几个 UCB 的学生为 Post-Ingres 开发了 SQL 的接口,正式发布了 PostgreSQL95,随后一步步在开源社区中成长起来),经过十几年的发展, PostgreSQL 已经成为世界上发展最快最受欢迎的数据库系统之一。\n本文章主要介绍在 CentOS 下源码编码安装 PostgreSQL-10.0 的一些简单步骤,以供参考。\n\n1. 新增用户组及用户\nPostgreSQL 默认是通过 postgres:postgres 来启动和使用的,因此在安装 PostgreSQL 前需要先创建 postgres 用户组及 postgres 用户。\n# 在root权限下进行\ngroupadd postgres # 添加postgres用户组\nuseradd postgres -g postgres # 添加postgres用户\npasswd postgres # 设置postgres用户密码\n2. 安装\n$ wget https://ftp.postgresql.org/pub/source/v10.0/postgresql-10.0.tar.gz\n$ tar zvxf postgresql-10.0.tar.gz\n$ cd postgresql-10.0\n$ ./configure --prefix=/data/softwares/pgsql\n$ make\n$ make install\n\n解决依赖:\nFAQ1:configure: error: readline library not found\n$ yum install readline-devel\n\nFAQ2:configure: error: zlib library not found\n$ yum install zlib-devel\n\n3. 启动\n# 新建数据库数据文件目录\n$ mkdir /data/softwares/pgsql/data\n \n# 新建数据库 log 文件目录\n$ mkdir /data/softwares/pgsql/log\n \n# 修改目录拥有者\n$ chown postgres:postgres /data/softwares/pgsql/data -R\n$ chown postgres:postgres /data/softwares/pgsql/log -R\n \n# 执行数据库初始化脚本\n$ su postgres\n$ /data/softwares/pgsql/bin/initdb --encoding=utf8 -D /data/softwares/pgsql/data\n \n# 启动 PostgreSQL 服务\n$ /data/softwares/pgsql/bin/pg_ctl -D /data/softwares/pgsql/data -l /data/softwares/pgsql/log/postgresql.log start #postgres 用户下执行\n \n# 登录 PostgreSQL 数据库\n$ psql\n\n\n4. 重启\n$ su postgres\n$ /data/softwares/pgsql/bin/pg_ctl -D /data/softwares/pgsql/data -l /data/softwares/pgsql/log/postgresql.log restart\n\n5. 设置开机启动\n解压后的 postgresql-x.x.x 下提供了基于 freebsd、linux、osx 3 个系统的 postgresql 启动命令。\n1)对于通过源码自定义安装的 pgsql,需要修改相关启动脚本:\n$ cd postgresql-10.0/postgresql-10.0/contrib/start-scripts\n$ vi linux\n......\n......\n# Installation prefix\nprefix=/data/softwares/pgsql\n \n# Data directory\nPGDATA="/data/softwares/pgsql/data"\n \n# Who to run the postmaster as, usually "postgres". (NOT "root")\nPGUSER=postgres\n \n# Where to keep a log file\nPGLOG="$PGDATA/serverlog"\n......\n......\n2)设置数据库开机启动:\n$ cp /data/softwares/source/postgresql-10.0/postgresql-10.0/contrib/start-scripts/linux /etc/init.d/postgresql\n\n# 添加执行权限\n$ chmod a+x /etc/init.d/postgresql\n\n# 添加至开机启动\n$ chkconfig --add postgresql\n$ chkconfig postgresql on\n3)查看 postgresql 状态\n$ service postgresql status\npg_ctl: server is running (PID: 32586)\n/data/softwares/pgsql/bin/postgres "-D" "/data/softwares/pgsql/data"\n6. 禁止管理员空密码登录\n在 PostgreSQL 中,如果你想禁止管理员(通常是 postgres 用户)使用空密码登录(正常情况下 postgres 用户可以直接使用 psql 命令直接登录 PostgreSQL),你可以通过修改 pg_hba.conf 文件来实现。\n\n\n找到你的 pg_hba.conf 文件。这个文件通常位于 PostgreSQL 的数据目录中,例如 /var/lib/pgsql/data 或 /etc/postgresql//main。\n\n\n修改 pg_hba.conf 文件,将管理员的登录方式从 trust 更改为 md5 或 password。这意味着所有连接,包括 postgres 用户的,都需要提供密码。\n\n\n例如,将以下行:\nlocal all postgres trust\n\n修改为:\nlocal all postgres md5\n\n\n重新加载或重启 PostgreSQL 服务以应用更改。\n\n重新加载配置的命令通常是:\npg_ctl reload\n或者重启服务:\nsystemctl restart postgresql\n或者在不同的系统中可能是:\nservice postgresql restart\n完成这些步骤后,postgres 用户将不能再使用空密码登录数据库。其他用户如果想登录数据库,也需要提供密码。', 'bodyHTML': '

PostgreSQL 是一个功能强大的开源对象关系数据库管理系统(ORDBMS),它从伯克利写的 POSTGRES 软件包发展而来(1995 年几个 UCB 的学生为 Post-Ingres 开发了 SQL 的接口,正式发布了 PostgreSQL95,随后一步步在开源社区中成长起来),经过十几年的发展, PostgreSQL 已经成为世界上发展最快最受欢迎的数据库系统之一。

\n

本文章主要介绍在 CentOS 下源码编码安装 PostgreSQL-10.0 的一些简单步骤,以供参考。

\n\n

1. 新增用户组及用户

\n

PostgreSQL 默认是通过 postgres:postgres 来启动和使用的,因此在安装 PostgreSQL 前需要先创建 postgres 用户组及 postgres 用户。

\n
# 在root权限下进行\ngroupadd postgres                    # 添加postgres用户组\nuseradd postgres -g postgres         # 添加postgres用户\npasswd postgres                      # 设置postgres用户密码
\n

2. 安装

\n
$ wget https://ftp.postgresql.org/pub/source/v10.0/postgresql-10.0.tar.gz\n$ tar zvxf postgresql-10.0.tar.gz\n$ cd postgresql-10.0\n$ ./configure --prefix=/data/softwares/pgsql\n$ make\n$ make install\n
\n

解决依赖:

\n
FAQ1:configure: error: readline library not found\n$ yum install readline-devel\n\nFAQ2:configure: error: zlib library not found\n$ yum install zlib-devel\n
\n

3. 启动

\n
# 新建数据库数据文件目录\n$ mkdir /data/softwares/pgsql/data\n \n# 新建数据库 log 文件目录\n$ mkdir /data/softwares/pgsql/log\n \n# 修改目录拥有者\n$ chown postgres:postgres /data/softwares/pgsql/data -R\n$ chown postgres:postgres /data/softwares/pgsql/log -R\n \n# 执行数据库初始化脚本\n$ su postgres\n$ /data/softwares/pgsql/bin/initdb --encoding=utf8 -D /data/softwares/pgsql/data\n \n# 启动 PostgreSQL 服务\n$ /data/softwares/pgsql/bin/pg_ctl -D /data/softwares/pgsql/data -l /data/softwares/pgsql/log/postgresql.log start    #postgres 用户下执行\n \n# 登录 PostgreSQL 数据库\n$ psql\n
\n

psql-db-list

\n

4. 重启

\n
$ su postgres\n$ /data/softwares/pgsql/bin/pg_ctl -D /data/softwares/pgsql/data -l /data/softwares/pgsql/log/postgresql.log restart\n
\n

5. 设置开机启动

\n

解压后的 postgresql-x.x.x 下提供了基于 freebsd、linux、osx 3 个系统的 postgresql 启动命令。

\n

1)对于通过源码自定义安装的 pgsql,需要修改相关启动脚本:

\n
$ cd postgresql-10.0/postgresql-10.0/contrib/start-scripts\n$ vi linux\n......\n......\n# Installation prefix\nprefix=/data/softwares/pgsql\n  \n# Data directory\nPGDATA="/data/softwares/pgsql/data"\n  \n# Who to run the postmaster as, usually "postgres".  (NOT "root")\nPGUSER=postgres\n  \n# Where to keep a log file\nPGLOG="$PGDATA/serverlog"\n......\n......
\n

2)设置数据库开机启动:

\n
$ cp /data/softwares/source/postgresql-10.0/postgresql-10.0/contrib/start-scripts/linux /etc/init.d/postgresql\n\n# 添加执行权限\n$ chmod a+x /etc/init.d/postgresql\n\n# 添加至开机启动\n$ chkconfig --add postgresql\n$ chkconfig postgresql on
\n

3)查看 postgresql 状态

\n
$ service postgresql status\npg_ctl: server is running (PID: 32586)\n/data/softwares/pgsql/bin/postgres "-D" "/data/softwares/pgsql/data"
\n

6. 禁止管理员空密码登录

\n

在 PostgreSQL 中,如果你想禁止管理员(通常是 postgres 用户)使用空密码登录(正常情况下 postgres 用户可以直接使用 psql 命令直接登录 PostgreSQL),你可以通过修改 pg_hba.conf 文件来实现。

\n
    \n
  1. \n

    找到你的 pg_hba.conf 文件。这个文件通常位于 PostgreSQL 的数据目录中,例如 /var/lib/pgsql/data/etc/postgresql/<version>/main

    \n
  2. \n
  3. \n

    修改 pg_hba.conf 文件,将管理员的登录方式从 trust 更改为 md5password。这意味着所有连接,包括 postgres 用户的,都需要提供密码。

    \n
  4. \n
\n

例如,将以下行:

\n
local   all             postgres                                trust\n
\n

修改为:

\n
local   all             postgres                                md5\n
\n
    \n
  1. 重新加载或重启 PostgreSQL 服务以应用更改。
  2. \n
\n

重新加载配置的命令通常是:

\n
pg_ctl reload
\n

或者重启服务:

\n
systemctl restart postgresql
\n

或者在不同的系统中可能是:

\n
service postgresql restart
\n

完成这些步骤后,postgres 用户将不能再使用空密码登录数据库。其他用户如果想登录数据库,也需要提供密码。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.4-数据库'}, 'labels': {'nodes': [{'name': '1.4.1-PostgreSQL'}]}, 'comments': {'nodes': []}}, {'title': 'R 包安装指定 GCC 和 G++ 并开启 C++11 支持', 'number': 85, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/85', 'createdAt': '2024-08-30T03:00:33Z', 'lastEditedAt': '2024-08-30T03:07:53Z', 'updatedAt': '2024-08-30T03:07:53Z', 'body': '如果你的 R 是使用比较低版本的 GCC(如 Red Hat 6.5 + GCC/G++ 4.4.7),但安装的 R 包需要开启 C++11 支持,或者需要更高版本的 GCC 和 G++,可以参考一下这个方法。\r\n\r\n\r\n\r\n首先,在 `home` 目录创建一个 `~/.R/Makevars` 文件。\r\n\r\n```bash\r\nmkdir ~/.R\r\nvi ~/.R/Makevars\r\n```\r\n\r\n然后,在 `Makevars` 文件中加入以下内容。\r\n\r\n```bash\r\nCXX11 = /opt/rh/devtoolset-7/root/usr/bin/g++ -std=c++11 -fPIC\r\nCXX14 = /opt/rh/devtoolset-7/root/usr/bin/g++\r\nCXX14FLAGS = -g -O2 $(LTO)\r\nCXX14PICFLAGS = -fpic\r\nCXX14STD = -std=gnu++14\r\n```\r\n\r\n最后,重新打开 R,执行对应包安装。\r\n\r\n```r\r\noptions("repos"=c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))\r\ninstall.packages("gridtext")\r\n```\r\n\r\n![install-packages-gridtext](https://kg.weiyan.cc/2024/08/install-packages-gridtext.webp)\r\n\r\n参考资料:\r\n\r\n1. [ERROR: compilation failed for package \'gridtext\' - wilkelab/gridtext#7](https://github.com/wilkelab/gridtext/issues/7)\r\n', 'bodyText': '如果你的 R 是使用比较低版本的 GCC(如 Red Hat 6.5 + GCC/G++ 4.4.7),但安装的 R 包需要开启 C++11 支持,或者需要更高版本的 GCC 和 G++,可以参考一下这个方法。\n\n首先,在 home 目录创建一个 ~/.R/Makevars 文件。\nmkdir ~/.R\nvi ~/.R/Makevars\n然后,在 Makevars 文件中加入以下内容。\nCXX11 = /opt/rh/devtoolset-7/root/usr/bin/g++ -std=c++11 -fPIC\nCXX14 = /opt/rh/devtoolset-7/root/usr/bin/g++\nCXX14FLAGS = -g -O2 $(LTO)\nCXX14PICFLAGS = -fpic\nCXX14STD = -std=gnu++14\n最后,重新打开 R,执行对应包安装。\noptions("repos"=c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))\ninstall.packages("gridtext")\n\n参考资料:\n\nERROR: compilation failed for package \'gridtext\' - wilkelab/gridtext#7', 'bodyHTML': '

如果你的 R 是使用比较低版本的 GCC(如 Red Hat 6.5 + GCC/G++ 4.4.7),但安装的 R 包需要开启 C++11 支持,或者需要更高版本的 GCC 和 G++,可以参考一下这个方法。

\n\n

首先,在 home 目录创建一个 ~/.R/Makevars 文件。

\n
mkdir ~/.R\nvi ~/.R/Makevars
\n

然后,在 Makevars 文件中加入以下内容。

\n
CXX11 = /opt/rh/devtoolset-7/root/usr/bin/g++ -std=c++11 -fPIC\nCXX14 = /opt/rh/devtoolset-7/root/usr/bin/g++\nCXX14FLAGS = -g -O2 $(LTO)\nCXX14PICFLAGS = -fpic\nCXX14STD = -std=gnu++14
\n

最后,重新打开 R,执行对应包安装。

\n
options("repos"=c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))\ninstall.packages("gridtext")
\n

install-packages-gridtext

\n

参考资料:

\n
    \n
  1. ERROR: compilation failed for package \'gridtext\' - wilkelab/gridtext#7
  2. \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '1.3.6-R'}]}, 'comments': {'nodes': []}}, {'title': '诛仙', 'number': 84, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/84', 'createdAt': '2024-08-20T03:55:13Z', 'lastEditedAt': '2024-08-20T04:23:23Z', 'updatedAt': '2024-08-20T04:23:23Z', 'body': '闲来看剧,无意中在腾讯视频看了几集《诛仙》动漫,虽然个别人物在建模还不算特别满意,但总体还是很不错,而且冲着对原著的高度还原,瞬间有种入坑不能自拔的感觉。\r\n\r\n\r\n\r\n第一次接触诛仙小说应该也是十几年前的事情,高一高二一度沉迷网络小说,一发不可收拾,断断续续的看了不少。惊叹于作者对于诛仙世界架构和故事逻辑,主副线也很完整,人物鲜活丰满,而且文笔也不错。最引人瞩目的当属主人公的感情纠葛,碧瑶的虽死不悔的爱,陆雪琪的温婉素雅和为了张小凡的付出都是让那时的我特别特别感动的,从当时来说,诛仙确实是非常可以带给人一种震撼的感觉的。 \r\n\r\n\r\n如今从动漫入局,又把原小说看了一遍,梦回青春年少的仙侠错觉,总有种说不清道不明的神奇滋味。', 'bodyText': '闲来看剧,无意中在腾讯视频看了几集《诛仙》动漫,虽然个别人物在建模还不算特别满意,但总体还是很不错,而且冲着对原著的高度还原,瞬间有种入坑不能自拔的感觉。\n\n第一次接触诛仙小说应该也是十几年前的事情,高一高二一度沉迷网络小说,一发不可收拾,断断续续的看了不少。惊叹于作者对于诛仙世界架构和故事逻辑,主副线也很完整,人物鲜活丰满,而且文笔也不错。最引人瞩目的当属主人公的感情纠葛,碧瑶的虽死不悔的爱,陆雪琪的温婉素雅和为了张小凡的付出都是让那时的我特别特别感动的,从当时来说,诛仙确实是非常可以带给人一种震撼的感觉的。\n如今从动漫入局,又把原小说看了一遍,梦回青春年少的仙侠错觉,总有种说不清道不明的神奇滋味。', 'bodyHTML': '

闲来看剧,无意中在腾讯视频看了几集《诛仙》动漫,虽然个别人物在建模还不算特别满意,但总体还是很不错,而且冲着对原著的高度还原,瞬间有种入坑不能自拔的感觉。

\n\n

第一次接触诛仙小说应该也是十几年前的事情,高一高二一度沉迷网络小说,一发不可收拾,断断续续的看了不少。惊叹于作者对于诛仙世界架构和故事逻辑,主副线也很完整,人物鲜活丰满,而且文笔也不错。最引人瞩目的当属主人公的感情纠葛,碧瑶的虽死不悔的爱,陆雪琪的温婉素雅和为了张小凡的付出都是让那时的我特别特别感动的,从当时来说,诛仙确实是非常可以带给人一种震撼的感觉的。

\n

如今从动漫入局,又把原小说看了一遍,梦回青春年少的仙侠错觉,总有种说不清道不明的神奇滋味。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '解决 GitHub 提交次数多导致仓库体积过大的问题', 'number': 83, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/83', 'createdAt': '2024-08-12T03:28:22Z', 'lastEditedAt': None, 'updatedAt': '2024-08-13T01:50:51Z', 'body': '提交代码要控制节奏,不能随心所欲,尤其是团队协作开发;如果发现 `.git` 目录太大,推荐使用 Git LFS 来管理大文件。\r\n\r\n\r\n\r\n参考以下几篇文章的解决方案:\r\n\r\n1. [被吐槽 GitHub仓 库太大,直接 600M 瘦身到 6M,这下舒服了](https://www.cnblogs.com/chengxy-nds/p/17306115.html) - 博客园\r\n2. [如何解决 GitHub 提交次数过多 .git 文件过大的问题?](https://www.zhihu.com/question/29769130) - 知乎', 'bodyText': '提交代码要控制节奏,不能随心所欲,尤其是团队协作开发;如果发现 .git 目录太大,推荐使用 Git LFS 来管理大文件。\n\n参考以下几篇文章的解决方案:\n\n被吐槽 GitHub仓 库太大,直接 600M 瘦身到 6M,这下舒服了 - 博客园\n如何解决 GitHub 提交次数过多 .git 文件过大的问题? - 知乎', 'bodyHTML': '

提交代码要控制节奏,不能随心所欲,尤其是团队协作开发;如果发现 .git 目录太大,推荐使用 Git LFS 来管理大文件。

\n\n

参考以下几篇文章的解决方案:

\n
    \n
  1. 被吐槽 GitHub仓 库太大,直接 600M 瘦身到 6M,这下舒服了 - 博客园
  2. \n
  3. 如何解决 GitHub 提交次数过多 .git 文件过大的问题? - 知乎
  4. \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '巴黎奥运', 'number': 82, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/82', 'createdAt': '2024-07-29T06:27:29Z', 'lastEditedAt': '2024-08-05T03:00:45Z', 'updatedAt': '2024-08-05T03:00:45Z', 'body': '2024 年的巴黎奥运会各项比赛正在如火如荼进行,但是在个人感官上,这一届的奥运会热度好像有点低。\r\n\r\n\r\n\r\n对于开幕式,有两点切身的感受比较深刻。一个是时间定于 7 月 27 日(星期六)凌晨,第二个是可以在电影院观看 2024 年巴黎奥运会开幕式直播。这些信息基于都是来源于自己在上班路上的听广播习惯,广州可进行奥运会开幕式观影预约的影院仅有 4 家,但需要达到最低拼场人数才可 "开团"!\r\n\r\n作为史上第一次把开幕式放在室外搞,也是首次摈弃以往步行进入体育场的传统,让运动员乘船沿着巴黎的"主干道" ——塞纳河前进。这届奥运会的确有点别出心裁。个人对于开幕式并没有什么特别值得期待的,也就事后通过各种短视频看了一下中国代表团出场、点燃圣火,以及其他零零散散的一些画面,感觉相比上一届的日本奥运会,巴黎奥运会给人印象更加深刻,文化底蕴、开放性、包容性都很不错,但也不可否认开幕式过后的各种两极分化评论,这的确也是争议性相当大的异常奥运会。\r\n\r\n奥运会最大的看点还是比赛。作为四年难得一遇的体育盛宴,各项赛程都很吸引人。\r\n\r\n个人最大的期待,还是在于羽毛球,小组赛的赛程也追了很多场,接下来依旧值得期待。跳水、游泳、排球、篮球,时间允许下肯定也是不能错过的。\r\n\r\n------\r\n\r\n记录一下那些自己看过的一些赛事,为这个夏天的运动健儿们加油。\r\n\r\n- 7 月 28 - 19:30 - 周日 篮球 | 女子小组赛 - A组(1):西班牙(90) VS 中国(89) \r\n 没顶住!女篮首战憾负西班牙! \r\n\r\n- 7 月 29 - 21:40 - 周一 羽毛球 | 男子双打小组赛 - D组(5):丹麦(2) VS 中国(0) \r\n \'badminton-0729\'\r\n\r\n- 7 月 30 - 20:30 - 周二 乒乓球 | 混合双打金牌赛:中国(4) VS 朝鲜(2) \r\n 乒乓球中国的首个奥运混双金牌!终于到手! \r\n \'ping-pong-china-korea-2024\'\r\n\r\n- 7 月 30 - 21:40 - 周二 羽毛球 | 男子双打小组赛 - D组(8):中国(2) VS 日本(0) \r\n 保木卓朗/小林优吾 vs 欧烜屹/刘雨辰,图欧组合终于赢了,不容易。 \r\n\r\n- 7 月 31 - 19:30 - 周三 篮球 | 女子小组赛 - A组(4):塞尔维亚(81) VS 中国(59) \r\n 两连败!中国女篮22分惨负塞尔维亚,看的揪心,后面两节完全被碾压! \r\n \'basketball-0731\'\r\n\r\n- 8 月 1 - 19:00 - 周四 羽毛球 | 男子双打1/4决赛(2):中国(2) VS 印尼(0) \r\n 梁王(梁伟铿/王昶) 2 比 0 胜双阿(阿尔菲安/阿迪安托),晋级巴黎奥运会 4 强! \r\n \'badminton-lw-paris-2024\'\r\n\r\n- 8 月 1 - 21:20 - 周四 羽毛球 | 男子单打16强赛(5):中国(0) VS 新加坡(2) \r\n 李诗沣 0 比 2 不敌骆建佑,脑子不够叠加勇气不够,战术执行不起来,输得不冤。。。 \r\n\r\n- 8 月 2 - 22:10 - 周五 羽毛球 | 混合双打金牌赛:中国(2)VS 韩国(0) \r\n 雅思组合(黄雅琼/郑思维)2:0 胜韩国金银组合(金元昊/郑那银),成就大满贯,圆梦巴黎!这场决赛不得不说,郑思维状态是真的好,打疯了! \r\n \'zheng-huang-paris-gold\' \r\n\r\n- 8 月 3 - 00:45 - 周六 羽毛球 | 男子单打1/4决赛(2) \r\n 爆冷,石宇奇 0-2 昆拉武特·威提讪,无缘羽毛球男单四强。第一次熬夜看的比赛,石头状态不好,战术上完全被压制,真的破防了! \r\n \'badminton-shiyuqi-paris-2024\' \r\n\r\n- 8 月 3 - 22:10 - 周六 羽毛球 | 女子双打金牌赛:中国(2)VS 中国(0) \r\n 凡尘组合(陈清晨/贾一凡)2:0 圣坛组合(谭宁/刘圣书),正如赛后她们身披国旗大喊 **"中国女双第一"**! \r\n \'badminton-women-gold-paris-2024\' \r\n\r\n- 8 月 4 - 20:30 - 周日 乒乓球 | 男子单打金牌赛 \r\n 4-1!樊振东击败莫雷加德勇夺男单冠军,成国乒第11位大满贯得主! \r\n \'fanzhendong-gold-paris-2024\'\r\n\r\n- 8 月 4 - 22:30 - 周日 羽毛球 | 男子双打金牌赛 \r\n 梁王组合(王昶/梁伟铿)1-2 惜败羚羊组合(李洋/王齐麟),遗憾摘银。接发球失误太多,加上随意挑战,顶着夺冠压力和政治压力打到决胜局的 19-21,也算尽力了! \r\n \'badminton-lw-silver-paris-2024\'\r\n\r\n\r\n ', 'bodyText': '2024 年的巴黎奥运会各项比赛正在如火如荼进行,但是在个人感官上,这一届的奥运会热度好像有点低。\n\n对于开幕式,有两点切身的感受比较深刻。一个是时间定于 7 月 27 日(星期六)凌晨,第二个是可以在电影院观看 2024 年巴黎奥运会开幕式直播。这些信息基于都是来源于自己在上班路上的听广播习惯,广州可进行奥运会开幕式观影预约的影院仅有 4 家,但需要达到最低拼场人数才可 "开团"!\n作为史上第一次把开幕式放在室外搞,也是首次摈弃以往步行进入体育场的传统,让运动员乘船沿着巴黎的"主干道" ——塞纳河前进。这届奥运会的确有点别出心裁。个人对于开幕式并没有什么特别值得期待的,也就事后通过各种短视频看了一下中国代表团出场、点燃圣火,以及其他零零散散的一些画面,感觉相比上一届的日本奥运会,巴黎奥运会给人印象更加深刻,文化底蕴、开放性、包容性都很不错,但也不可否认开幕式过后的各种两极分化评论,这的确也是争议性相当大的异常奥运会。\n奥运会最大的看点还是比赛。作为四年难得一遇的体育盛宴,各项赛程都很吸引人。\n个人最大的期待,还是在于羽毛球,小组赛的赛程也追了很多场,接下来依旧值得期待。跳水、游泳、排球、篮球,时间允许下肯定也是不能错过的。\n\n记录一下那些自己看过的一些赛事,为这个夏天的运动健儿们加油。\n\n\n7 月 28 - 19:30 - 周日 篮球 | 女子小组赛 - A组(1):西班牙(90) VS 中国(89)\n没顶住!女篮首战憾负西班牙!\n\n\n7 月 29 - 21:40 - 周一 羽毛球 | 男子双打小组赛 - D组(5):丹麦(2) VS 中国(0)\n\n\n\n7 月 30 - 20:30 - 周二 乒乓球 | 混合双打金牌赛:中国(4) VS 朝鲜(2)\n乒乓球中国的首个奥运混双金牌!终于到手!\n\n\n\n7 月 30 - 21:40 - 周二 羽毛球 | 男子双打小组赛 - D组(8):中国(2) VS 日本(0)\n保木卓朗/小林优吾 vs 欧烜屹/刘雨辰,图欧组合终于赢了,不容易。\n\n\n7 月 31 - 19:30 - 周三 篮球 | 女子小组赛 - A组(4):塞尔维亚(81) VS 中国(59)\n两连败!中国女篮22分惨负塞尔维亚,看的揪心,后面两节完全被碾压!\n\n\n\n8 月 1 - 19:00 - 周四 羽毛球 | 男子双打1/4决赛(2):中国(2) VS 印尼(0)\n梁王(梁伟铿/王昶) 2 比 0 胜双阿(阿尔菲安/阿迪安托),晋级巴黎奥运会 4 强!\n\n\n\n8 月 1 - 21:20 - 周四 羽毛球 | 男子单打16强赛(5):中国(0) VS 新加坡(2)\n李诗沣 0 比 2 不敌骆建佑,脑子不够叠加勇气不够,战术执行不起来,输得不冤。。。\n\n\n8 月 2 - 22:10 - 周五 羽毛球 | 混合双打金牌赛:中国(2)VS 韩国(0)\n雅思组合(黄雅琼/郑思维)2:0 胜韩国金银组合(金元昊/郑那银),成就大满贯,圆梦巴黎!这场决赛不得不说,郑思维状态是真的好,打疯了!\n\n\n\n8 月 3 - 00:45 - 周六 羽毛球 | 男子单打1/4决赛(2)\n爆冷,石宇奇 0-2 昆拉武特·威提讪,无缘羽毛球男单四强。第一次熬夜看的比赛,石头状态不好,战术上完全被压制,真的破防了!\n\n\n\n8 月 3 - 22:10 - 周六 羽毛球 | 女子双打金牌赛:中国(2)VS 中国(0)\n凡尘组合(陈清晨/贾一凡)2:0 圣坛组合(谭宁/刘圣书),正如赛后她们身披国旗大喊 "中国女双第一"!\n\n\n\n8 月 4 - 20:30 - 周日 乒乓球 | 男子单打金牌赛\n4-1!樊振东击败莫雷加德勇夺男单冠军,成国乒第11位大满贯得主!\n\n\n\n8 月 4 - 22:30 - 周日 羽毛球 | 男子双打金牌赛\n梁王组合(王昶/梁伟铿)1-2 惜败羚羊组合(李洋/王齐麟),遗憾摘银。接发球失误太多,加上随意挑战,顶着夺冠压力和政治压力打到决胜局的 19-21,也算尽力了!', 'bodyHTML': '

2024 年的巴黎奥运会各项比赛正在如火如荼进行,但是在个人感官上,这一届的奥运会热度好像有点低。

\n\n

对于开幕式,有两点切身的感受比较深刻。一个是时间定于 7 月 27 日(星期六)凌晨,第二个是可以在电影院观看 2024 年巴黎奥运会开幕式直播。这些信息基于都是来源于自己在上班路上的听广播习惯,广州可进行奥运会开幕式观影预约的影院仅有 4 家,但需要达到最低拼场人数才可 "开团"!

\n

作为史上第一次把开幕式放在室外搞,也是首次摈弃以往步行进入体育场的传统,让运动员乘船沿着巴黎的"主干道" ——塞纳河前进。这届奥运会的确有点别出心裁。个人对于开幕式并没有什么特别值得期待的,也就事后通过各种短视频看了一下中国代表团出场、点燃圣火,以及其他零零散散的一些画面,感觉相比上一届的日本奥运会,巴黎奥运会给人印象更加深刻,文化底蕴、开放性、包容性都很不错,但也不可否认开幕式过后的各种两极分化评论,这的确也是争议性相当大的异常奥运会。

\n

奥运会最大的看点还是比赛。作为四年难得一遇的体育盛宴,各项赛程都很吸引人。

\n

个人最大的期待,还是在于羽毛球,小组赛的赛程也追了很多场,接下来依旧值得期待。跳水、游泳、排球、篮球,时间允许下肯定也是不能错过的。

\n
\n

记录一下那些自己看过的一些赛事,为这个夏天的运动健儿们加油。

\n
    \n
  • \n

    7 月 28 - 19:30 - 周日 篮球 | 女子小组赛 - A组(1):西班牙(90) VS 中国(89)
    \n没顶住!女篮首战憾负西班牙!

    \n
  • \n
  • \n

    7 月 29 - 21:40 - 周一 羽毛球 | 男子双打小组赛 - D组(5):丹麦(2) VS 中国(0)
    \nbadminton-0729

    \n
  • \n
  • \n

    7 月 30 - 20:30 - 周二 乒乓球 | 混合双打金牌赛:中国(4) VS 朝鲜(2)
    \n乒乓球中国的首个奥运混双金牌!终于到手!
    \nping-pong-china-korea-2024

    \n
  • \n
  • \n

    7 月 30 - 21:40 - 周二 羽毛球 | 男子双打小组赛 - D组(8):中国(2) VS 日本(0)
    \n保木卓朗/小林优吾 vs 欧烜屹/刘雨辰,图欧组合终于赢了,不容易。

    \n
  • \n
  • \n

    7 月 31 - 19:30 - 周三 篮球 | 女子小组赛 - A组(4):塞尔维亚(81) VS 中国(59)
    \n两连败!中国女篮22分惨负塞尔维亚,看的揪心,后面两节完全被碾压!
    \nbasketball-0731

    \n
  • \n
  • \n

    8 月 1 - 19:00 - 周四 羽毛球 | 男子双打1/4决赛(2):中国(2) VS 印尼(0)
    \n梁王(梁伟铿/王昶) 2 比 0 胜双阿(阿尔菲安/阿迪安托),晋级巴黎奥运会 4 强!
    \nbadminton-lw-paris-2024

    \n
  • \n
  • \n

    8 月 1 - 21:20 - 周四 羽毛球 | 男子单打16强赛(5):中国(0) VS 新加坡(2)
    \n李诗沣 0 比 2 不敌骆建佑,脑子不够叠加勇气不够,战术执行不起来,输得不冤。。。

    \n
  • \n
  • \n

    8 月 2 - 22:10 - 周五 羽毛球 | 混合双打金牌赛:中国(2)VS 韩国(0)
    \n雅思组合(黄雅琼/郑思维)2:0 胜韩国金银组合(金元昊/郑那银),成就大满贯,圆梦巴黎!这场决赛不得不说,郑思维状态是真的好,打疯了!
    \nzheng-huang-paris-gold

    \n
  • \n
  • \n

    8 月 3 - 00:45 - 周六 羽毛球 | 男子单打1/4决赛(2)
    \n爆冷,石宇奇 0-2 昆拉武特·威提讪,无缘羽毛球男单四强。第一次熬夜看的比赛,石头状态不好,战术上完全被压制,真的破防了!
    \nbadminton-shiyuqi-paris-2024

    \n
  • \n
  • \n

    8 月 3 - 22:10 - 周六 羽毛球 | 女子双打金牌赛:中国(2)VS 中国(0)
    \n凡尘组合(陈清晨/贾一凡)2:0 圣坛组合(谭宁/刘圣书),正如赛后她们身披国旗大喊 "中国女双第一"
    \nbadminton-women-gold-paris-2024

    \n
  • \n
  • \n

    8 月 4 - 20:30 - 周日 乒乓球 | 男子单打金牌赛
    \n4-1!樊振东击败莫雷加德勇夺男单冠军,成国乒第11位大满贯得主!
    \nfanzhendong-gold-paris-2024

    \n
  • \n
  • \n

    8 月 4 - 22:30 - 周日 羽毛球 | 男子双打金牌赛
    \n梁王组合(王昶/梁伟铿)1-2 惜败羚羊组合(李洋/王齐麟),遗憾摘银。接发球失误太多,加上随意挑战,顶着夺冠压力和政治压力打到决胜局的 19-21,也算尽力了!
    \nbadminton-lw-silver-paris-2024

    \n
  • \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '寒冬将至', 'number': 81, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/81', 'createdAt': '2024-07-15T02:24:05Z', 'lastEditedAt': '2024-07-15T02:38:07Z', 'updatedAt': '2024-08-16T02:39:26Z', 'body': "经济不景气,就像一股寒风,吹得人心颤颤,市场更是进入严冬,就业、消费和投资都变得如履薄冰。\r\n\r\n\r\n\r\n从最近身边的很多人身上,由于大环境不景气带来的裁员比比皆是,IVD 行业、生信行业订单以肉眼可见的速度越来越少,小公司首先扛不住开启裁员,大公司从考核到绩效各种手段轮番上阵。\r\n\r\n\r\n\r\n好一点的公司 N+1 赔偿,但凤毛麟角;次一点的公司礼仪性的赔偿 1、2 个月的工资;更多的是领完当月工资走人;更有甚者,老板跑路,变相裁人的 ......\r\n\r\n裁人失业年年有,今年的暴风雨可能会更加猛烈些。铁打的营盘,流水的兵,除了比比谁更卷,还是要多思考一下自身的选择和规划。", 'bodyText': '经济不景气,就像一股寒风,吹得人心颤颤,市场更是进入严冬,就业、消费和投资都变得如履薄冰。\n\n从最近身边的很多人身上,由于大环境不景气带来的裁员比比皆是,IVD 行业、生信行业订单以肉眼可见的速度越来越少,小公司首先扛不住开启裁员,大公司从考核到绩效各种手段轮番上阵。\n\n好一点的公司 N+1 赔偿,但凤毛麟角;次一点的公司礼仪性的赔偿 1、2 个月的工资;更多的是领完当月工资走人;更有甚者,老板跑路,变相裁人的 ......\n裁人失业年年有,今年的暴风雨可能会更加猛烈些。铁打的营盘,流水的兵,除了比比谁更卷,还是要多思考一下自身的选择和规划。', 'bodyHTML': '

经济不景气,就像一股寒风,吹得人心颤颤,市场更是进入严冬,就业、消费和投资都变得如履薄冰。

\n\n

从最近身边的很多人身上,由于大环境不景气带来的裁员比比皆是,IVD 行业、生信行业订单以肉眼可见的速度越来越少,小公司首先扛不住开启裁员,大公司从考核到绩效各种手段轮番上阵。

\n

\n

好一点的公司 N+1 赔偿,但凤毛麟角;次一点的公司礼仪性的赔偿 1、2 个月的工资;更多的是领完当月工资走人;更有甚者,老板跑路,变相裁人的 ......

\n

裁人失业年年有,今年的暴风雨可能会更加猛烈些。铁打的营盘,流水的兵,除了比比谁更卷,还是要多思考一下自身的选择和规划。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': [{'body': '更加艰难了', 'author': {'login': 'obaby'}}]}}, {'title': '晒桌面', 'number': 80, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/80', 'createdAt': '2024-07-08T03:43:13Z', 'lastEditedAt': None, 'updatedAt': '2024-07-08T03:43:14Z', 'body': '文艺男青年对于烟火气息的干净整洁桌面总有一种迷之吸引,热衷于各种晒桌面带来的解压感,其中的细节让我觉得这才是生活应该有的部分,尤其在这样的桌面上摆上各种我喜欢的影音娱乐设备,更能点亮我的生活。\r\n\r\n', 'bodyText': '文艺男青年对于烟火气息的干净整洁桌面总有一种迷之吸引,热衷于各种晒桌面带来的解压感,其中的细节让我觉得这才是生活应该有的部分,尤其在这样的桌面上摆上各种我喜欢的影音娱乐设备,更能点亮我的生活。', 'bodyHTML': '

文艺男青年对于烟火气息的干净整洁桌面总有一种迷之吸引,热衷于各种晒桌面带来的解压感,其中的细节让我觉得这才是生活应该有的部分,尤其在这样的桌面上摆上各种我喜欢的影音娱乐设备,更能点亮我的生活。

\n', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'Python 陷阱之 strip、lstrip、rstrip 可以删除比预期更多的内容', 'number': 79, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/79', 'createdAt': '2024-07-03T08:05:40Z', 'lastEditedAt': None, 'updatedAt': '2024-07-03T08:05:40Z', 'body': '> 原文:[Python Gotcha: strip, lstrip, rstrip can remove more than expected](https://andrewwegner.com/python-gotcha-strip-functions-unexpected-behavior.html)\r\n\r\n## 介绍\r\n\r\n作为一名软件工程师,你处理过不少脏字符串。删除用户输入中的前导或尾随空格可能是最常见的工作之一。\r\n\r\n在 Python 中,这是通过 `.strip()` 、 `.lstrip()` 或 `.rstrip()` 函数完成的,通常如下所示:\r\n```python\r\n>>> " Andrew Wegner ".lower().strip()\r\n\'andrew wegner\'\r\n>>> " Andrew Wegner ".lower().lstrip()\r\n\'andrew wegner \'\r\n>>> " Andrew Wegner ".lower().rstrip()\r\n\' andrew wegner\'\r\n```\r\n\r\n这非常简单,并且没有什么意外的事情发生。\r\n\r\n## 陷阱\r\n\r\n陷阱在于,这些函数中的每一个都可以接受一个要删除的字符列表。\r\n\r\n```python\r\n>>> "Andrew Wegner".lower().rstrip(" wegner")\r\n\'and\'\r\n```\r\n\r\n发生了什么?为什么结果不只是:\r\n```bash\r\n\'andrew\'\r\n```\r\n\r\n## 解释\r\n\r\n再次仔细阅读文档中的这行说明:\r\n\r\n> A list of **characters**\r\n\r\n不是字符串列表 (Not a list of strings.)。\r\n\r\n> [str.rstrip([chars])](https://docs.python.org/3/library/stdtypes.html#str.rstrip)\r\n> \r\n> Return a copy of the string with trailing characters removed. The chars argument is a string specifying the set of characters to be removed. If omitted or `None`, the chars argument defaults to removing whitespace. The chars argument is **not a suffix**; rather, **all combinations of its values are stripped**.\r\n> \r\n> From [Built-in Types — Python 3.12.4 documentation](https://docs.python.org/3/library/stdtypes.html)\r\n\r\n文档中已经明确并举例说明了这一行为及其含义。然而,对于新开发者来说,这是出乎意料的行为。毕竟,这些函数看起来都很直观。\r\n\r\n我的示例执行以下操作:\r\n', 'bodyText': '原文:Python Gotcha: strip, lstrip, rstrip can remove more than expected\n\n介绍\n作为一名软件工程师,你处理过不少脏字符串。删除用户输入中的前导或尾随空格可能是最常见的工作之一。\n在 Python 中,这是通过 .strip() 、 .lstrip() 或 .rstrip() 函数完成的,通常如下所示:\n>>> " Andrew Wegner ".lower().strip()\n\'andrew wegner\'\n>>> " Andrew Wegner ".lower().lstrip()\n\'andrew wegner \'\n>>> " Andrew Wegner ".lower().rstrip()\n\' andrew wegner\'\n这非常简单,并且没有什么意外的事情发生。\n陷阱\n陷阱在于,这些函数中的每一个都可以接受一个要删除的字符列表。\n>>> "Andrew Wegner".lower().rstrip(" wegner")\n\'and\'\n发生了什么?为什么结果不只是:\n\'andrew\'\n解释\n再次仔细阅读文档中的这行说明:\n\nA list of characters\n\n不是字符串列表 (Not a list of strings.)。\n\nstr.rstrip([chars])\nReturn a copy of the string with trailing characters removed. The chars argument is a string specifying the set of characters to be removed. If omitted or None, the chars argument defaults to removing whitespace. The chars argument is not a suffix; rather, all combinations of its values are stripped.\nFrom Built-in Types — Python 3.12.4 documentation\n\n文档中已经明确并举例说明了这一行为及其含义。然而,对于新开发者来说,这是出乎意料的行为。毕竟,这些函数看起来都很直观。\n我的示例执行以下操作:', 'bodyHTML': '
\n

原文:Python Gotcha: strip, lstrip, rstrip can remove more than expected

\n
\n

介绍

\n

作为一名软件工程师,你处理过不少脏字符串。删除用户输入中的前导或尾随空格可能是最常见的工作之一。

\n

在 Python 中,这是通过 .strip().lstrip().rstrip() 函数完成的,通常如下所示:

\n
>>> "     Andrew Wegner     ".lower().strip()\n\'andrew wegner\'\n>>> "     Andrew Wegner     ".lower().lstrip()\n\'andrew wegner     \'\n>>> "     Andrew Wegner     ".lower().rstrip()\n\'     andrew wegner\'
\n

这非常简单,并且没有什么意外的事情发生。

\n

陷阱

\n

陷阱在于,这些函数中的每一个都可以接受一个要删除的字符列表。

\n
>>> "Andrew Wegner".lower().rstrip(" wegner")\n\'and\'
\n

发生了什么?为什么结果不只是:

\n
\'andrew\'
\n

解释

\n

再次仔细阅读文档中的这行说明:

\n
\n

A list of characters

\n
\n

不是字符串列表 (Not a list of strings.)。

\n
\n

str.rstrip([chars])

\n

Return a copy of the string with trailing characters removed. The chars argument is a string specifying the set of characters to be removed. If omitted or None, the chars argument defaults to removing whitespace. The chars argument is not a suffix; rather, all combinations of its values are stripped.

\n

From Built-in Types — Python 3.12.4 documentation

\n
\n

文档中已经明确并举例说明了这一行为及其含义。然而,对于新开发者来说,这是出乎意料的行为。毕竟,这些函数看起来都很直观。

\n

我的示例执行以下操作:

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.2-编程'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '手机', 'number': 78, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/78', 'createdAt': '2024-06-25T07:05:40Z', 'lastEditedAt': None, 'updatedAt': '2024-06-25T07:05:40Z', 'body': '手机对大部分人来说,现在更像是一个外置的私密部位:能随意触碰的人只有自己,伴侣想碰也得防着,只有万不得已的时候,才能交到专业人士手上(指修手机的)。\r\n\r\n', 'bodyText': '手机对大部分人来说,现在更像是一个外置的私密部位:能随意触碰的人只有自己,伴侣想碰也得防着,只有万不得已的时候,才能交到专业人士手上(指修手机的)。', 'bodyHTML': '

手机对大部分人来说,现在更像是一个外置的私密部位:能随意触碰的人只有自己,伴侣想碰也得防着,只有万不得已的时候,才能交到专业人士手上(指修手机的)。

\n', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '最舒服的字号和字体大小', 'number': 77, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/77', 'createdAt': '2024-06-18T02:19:36Z', 'lastEditedAt': '2024-06-18T02:24:11Z', 'updatedAt': '2024-06-18T02:24:11Z', 'body': '最舒服的字号目前没有确切的定论,默认的微软雅黑还能接受。但是在字体大小这一块,个人对小字体情有独钟。\r\n\r\n\r\n\r\n在手机端一直都会把系统(或者是常用 APP)的字体设置为最小,很重要的一个原因就是能在一页上容纳更多的信息,排版布局看起来更加舒服。在知乎看到有人说喜欢用小字体的人,其性格可能会相对内向,日常生活中并不是特别外向开放的人,或许也有一定的道理。\r\n\r\n浏览器端最常用的 Google Chrome 和备用的 Edge 用的也是 **14px** 的字体大小。 \r\n\r\n![chrome-14px](https://kg.weiyan.cc/2024/06/chrome-14px.png)', 'bodyText': '最舒服的字号目前没有确切的定论,默认的微软雅黑还能接受。但是在字体大小这一块,个人对小字体情有独钟。\n\n在手机端一直都会把系统(或者是常用 APP)的字体设置为最小,很重要的一个原因就是能在一页上容纳更多的信息,排版布局看起来更加舒服。在知乎看到有人说喜欢用小字体的人,其性格可能会相对内向,日常生活中并不是特别外向开放的人,或许也有一定的道理。\n浏览器端最常用的 Google Chrome 和备用的 Edge 用的也是 14px 的字体大小。', 'bodyHTML': '

最舒服的字号目前没有确切的定论,默认的微软雅黑还能接受。但是在字体大小这一块,个人对小字体情有独钟。

\n\n

在手机端一直都会把系统(或者是常用 APP)的字体设置为最小,很重要的一个原因就是能在一页上容纳更多的信息,排版布局看起来更加舒服。在知乎看到有人说喜欢用小字体的人,其性格可能会相对内向,日常生活中并不是特别外向开放的人,或许也有一定的道理。

\n

浏览器端最常用的 Google Chrome 和备用的 Edge 用的也是 14px 的字体大小。

\n

chrome-14px

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '生活的后花园', 'number': 76, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/76', 'createdAt': '2024-06-12T03:34:57Z', 'lastEditedAt': '2024-08-22T02:07:10Z', 'updatedAt': '2024-08-22T02:07:10Z', 'body': '年纪越大,越期待短暂的一些独处时光,安静且惬意。\r\n\r\n不知道大家的后花园都是什么,在 V2EX 看到,对有些人来说,备菜+做饭的一个小时,不接收外界信息,完全沉浸在只有自己的世界里,是他近几年找到了最好的放松方式了。对我自己可能就在于游戏+看电影,但是能有这样时间的机会确实不多。\r\n\r\n\r\n\r\n看到有人说家里玩游戏会有压力,这一点是同意的,尤其有了娃以后,放空自己的机会就更少了。所以,建立自己的精神后花园,去运运动其实也是一个不错的选择。', 'bodyText': '年纪越大,越期待短暂的一些独处时光,安静且惬意。\n不知道大家的后花园都是什么,在 V2EX 看到,对有些人来说,备菜+做饭的一个小时,不接收外界信息,完全沉浸在只有自己的世界里,是他近几年找到了最好的放松方式了。对我自己可能就在于游戏+看电影,但是能有这样时间的机会确实不多。\n\n看到有人说家里玩游戏会有压力,这一点是同意的,尤其有了娃以后,放空自己的机会就更少了。所以,建立自己的精神后花园,去运运动其实也是一个不错的选择。', 'bodyHTML': '

年纪越大,越期待短暂的一些独处时光,安静且惬意。

\n

不知道大家的后花园都是什么,在 V2EX 看到,对有些人来说,备菜+做饭的一个小时,不接收外界信息,完全沉浸在只有自己的世界里,是他近几年找到了最好的放松方式了。对我自己可能就在于游戏+看电影,但是能有这样时间的机会确实不多。

\n\n

看到有人说家里玩游戏会有压力,这一点是同意的,尤其有了娃以后,放空自己的机会就更少了。所以,建立自己的精神后花园,去运运动其实也是一个不错的选择。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': [{'body': '其实我们需要的是随心所欲的生活片段。', 'author': {'login': 'immelon0097'}}]}}, {'title': '使用 Python 的 argparse 构建命令行界面', 'number': 75, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/75', 'createdAt': '2024-06-06T06:23:52Z', 'lastEditedAt': '2024-06-07T08:35:09Z', 'updatedAt': '2024-06-07T08:35:09Z', 'body': '> 原文:[Build Command-Line Interfaces With Python\'s argparse](https://realpython.com/command-line-interfaces-python-argparse/) \r\n\r\n\r\n命令行应用在普通用户空间中可能并不常见,但它们存在于开发、数据科学、系统管理和许多其他操作中。每个命令行应用都需要一个用户友好的命令行界面 (CLI),以便你可以与应用本身进行交互。在 Python 中,您可以使用标准库中的 `argparse` 模块创建功能齐全的 CLI。\r\n\r\n\r\n\r\n在本文中,你将了解如何: \r\n\r\n- 命令行界面入门;\r\n- 在 Python 中组织和布局命令行应用项目;\r\n- 使用 Python `argparse` 创建命令行界面(command-line interfaces);\r\n- 使用 `argparse` 一些强大的功能深度自定义您的 CLI;\r\n\r\n若要充分利用本教程,应熟悉 Python 编程,包括面向对象编程、脚本开发和执行以及 Python 包和模块等概念。如果您熟悉与使用命令行或终端相关的一般概念和主题,这也将很有帮助。\r\n\r\n## 了解命令行界面\r\n\r\n自从计算机发明以来,人类一直需要并找到与这些机器交互和共享信息的方法。信息交换在人、计算机软件和硬件组件之间流动。其中任意两个元素之间的共享边界通常称为接口([interface](https://en.wikipedia.org/wiki/Interface_(computing)))。\r\n\r\n在软件开发中,接口是给定软件的特殊部分,它允许计算机系统组件之间的交互。当涉及到人机交互和软件交互时,这个重要的组件被称为用户界面([user interface](https://en.wikipedia.org/wiki/User_interface))。\r\n\r\n您会在编程中找到不同类型的用户界面。图形用户界面 (GUI) 可能是当今最常见的。但是,您还可以找到为其用户提供命令行界面 (CLI) 的应用和程序。在本教程中,你将了解 CLI 以及如何在 Python 中创建它们。\r\n\r\n## 命令行界面 (CLI)\r\n\r\n命令行界面允许您通过操作系统命令行、终端或控制台与应用程序或程序进行交互。\r\n\r\n要了解命令行界面及其工作原理,请考虑此实际示例。假设您有一个名为 sample 包含三个示例文件的目录。如果您使用的是类 Unix 操作系统,例如 Linux 或 macOS,请继续在父目录中打开命令行窗口或终端,然后执行以下命令: \r\n```bash\r\n$ ls sample/\r\nhello.txt lorem.md realpython.md\r\n```\r\n\r\nUnix 的 `ls` 命令列出目标目录中包含的文件和子目录,该目录默认为当前工作目录。上面的命令调用没有显示有关 的内容 sample 的太多信息。它只在屏幕上显示文件名。\r\n\r\n假设你想要获取有关目录及其内容的更丰富信息,那么你不需要寻找其他程序,因为 ls 命令有一个功能齐全的命令行界面,并且提供了一组有用的选项,可以用来定制命令的行为。\r\n\r\n例如,继续执行带有 `-l` 选项的 `ls` 命令: \r\n```bash\r\n$ ls -l sample/\r\ntotal 24\r\n-rw-r--r--@ 1 user staff 83 Aug 17 22:15 hello.txt\r\n-rw-r--r--@ 1 user staff 2609 Aug 17 22:15 lorem.md\r\n-rw-r--r--@ 1 user staff 428 Aug 17 22:15 realpython.md\r\n```\r\n\r\n现在,`ls` 命令的输出完全不同了。该命令显示了有关 sample 目录中文件的更多信息,包括权限、所有者、组、日期和大小。它还显示了这些文件在你计算机磁盘上使用的总空间。\r\n\r\n这种更丰富的输出结果是由于使用了 `-l` 选项,这是 Unix `ls` 命令行界面的一部分,它启用了详细的输出格式。\r\n\r\n## 命令、参数、选项、参数和子命令\r\n\r\n在本教程中,您将深入了解**命令**(commands)及其**子命令**(subcommands),同时还会学习到**命令行参数**(command-line arguments)、**选项**(options)和**参数**(parameters)的相关知识。因此,建议您将这些术语纳入您的技术词汇库中。\r\n\r\n- **命令(Command)**:在命令行或终端窗口中运行的程序或例程。通常,您可以通过其背后的程序(underlying program)或例程(routine)的名称来识别一个命令。 \r\n- **参数(Argument)**:命令在执行其预期操作时所需或可选的信息片段。命令通常接受一个或多个参数,您可以在命令行中以空格分隔或逗号分隔的列表形式提供这些参数。 \r\n- **选项(Option)**,也称为 **flag** 或 **switch**:一种可选的参数,用于修改命令的行为。选项通过特定的名称(如前一个示例中的 `-l`)传递给命令。 \r\n- **参数(Parameter)**:一个选项用于执行其预期操作或动作时所使用的参数。 \r\n- 子命令(Subcommand)**:一个预定义的名称,可以传递给应用程序来执行特定的操作。\r\n\r\n参考上一节中的示例命令结构:\r\n```bash\r\n$ ls -l sample/\r\n```\r\n\r\n在这个例子中,您组合了命令行界面(CLI)的以下组件: \r\n\r\n- **ls**:命令的名称或应用的名称;\r\n- **-l**:启用详细输出的选项(option)、开关(switch)或标志(flag); \r\n- **sample**:为命令执行提供附加信息的参数(argument); \r\n\r\n现在,让我们来看下面的命令结构,它展示了 Python 包管理器 `pip` 的命令行界面(CLI): \r\n```bash\r\n$ pip install -r requirements.txt\r\n```\r\n\r\n这是一个常见的 `pip` 命令结构,您可能之前已经见过。它允许您使用 `requirements.txt` 文件来给指定的 Python 项目安装依赖项。在这个例子中,您使用了以下命令行界面(CLI)组件: \r\n \r\n- **pip**:命令的名称;\r\n- **install**:`pip` 的子命令(subcommand)名称;\r\n- **-r**:`install` 子命令的选项(option);\r\n- **requirements.txt**:一个参数,特别是 `-r` 选项的参数。\r\n\r\n现在您已经了解了命令行界面(CLI)是什么以及其主要部分或组件有哪些。接下来,是时候学习如何在 Python 中创建自己的 CLI 了。\r\n\r\n## Python 中的 CLI 入门\r\n\r\nPython 附带了一些工具,这些工具可帮助您为程序和应用程序编写命令行界面(CLI)。若您需要快速为小型程序构建一个简洁的 CLI,那么可以利用 [`sys`](https://docs.python.org/3/library/sys.html#module-sys) 模块中的 [`argv`](https://docs.python.org/3/library/sys.html#sys.argv) 属性。这个属性会自动存储您在命令行中传递给特定程序的参数。\r\n\r\n### 使用 `sys.argv` 构建最小的 CLI\r\n\r\n以使用 `argv` 创建最小命令行界面(CLI)为例,假设您需要编写一个小程序,该程序类似于 `ls` 命令,能够列出给定目录下的所有文件。在这种情况下,您可以编写如下代码: \r\n```python\r\n# ls_argv.py\r\n\r\nimport sys\r\nfrom pathlib import Path\r\n\r\nif (args_count := len(sys.argv)) > 2:\r\n print(f"One argument expected, got {args_count - 1}")\r\n raise SystemExit(2)\r\nelif args_count < 2:\r\n print("You must specify the target directory")\r\n raise SystemExit(2)\r\n\r\ntarget_dir = Path(sys.argv[1])\r\n\r\nif not target_dir.is_dir():\r\n print("The target directory doesn\'t exist")\r\n raise SystemExit(1)\r\n\r\nfor entry in target_dir.iterdir():\r\n print(entry.name)\r\n```\r\n\r\n该程序通过手动处理命令行提供的参数来实现了一个简单的命令行界面(CLI),这些参数会自动存储在 `sys.argv` 中。`sys.argv` 的第一个元素始终是程序名称,第二个元素则是目标目录。由于应用程序不应接受超过一个目标目录,因此 `args_count` 不得超过 2。\r\n\r\n在检查 `sys.argv` 的内容后,您创建一个`pathlib.Path`对象来存储目标目录的路径。如果该目录不存在,您将通知用户并退出程序。接下来的`for`循环将列出目录内容,每行一个条目。\r\n\r\n如果从命令行运行该脚本,您将得到以下结果: \r\n```bash\r\n$ python ls_argv.py sample/\r\nhello.txt\r\nlorem.md\r\nrealpython.md\r\n\r\n$ python ls_argv.py\r\nYou must specify the target directory\r\n\r\n$ python ls_argv.py sample/ other_dir/\r\nOne argument expected, got 2\r\n\r\n$ python ls_argv.py non_existing/\r\nThe target directory doesn\'t exist\r\n```\r\n\r\n您的程序接受一个目录作为参数,并列出其内容。如果您运行命令时没有提供参数,您将收到一个错误消息。如果您运行命令时指定了超过一个目标目录,您同样会收到一个错误消息。如果尝试运行命令并指定一个不存在的目录,程序将输出另一个错误消息。\r\n\r\n虽然您的程序运行正常,但对于更复杂的 CLI 应用程序来说,使用`sys.argv`属性手动解析命令行参数并不是一个可扩展的解决方案。如果您的应用需要接受更多的参数和选项,那么解析`sys.argv`将变得复杂且容易出错。您需要一个更好的解决方案,这就是 Python 中的`argparse`模块所提供的。\r\n\r\n### 使用 `argparse` 创建 CLI\r\n\r\n在 Python 中创建 CLI 应用程序的更便捷方法是使用标准库中的 [`argparse`](https://docs.python.org/3/library/argparse.html?highlight=argparse#module-argparse) 模块。该模块首次在 Python 3.2 中随 [PEP-389](https://www.python.org/dev/peps/pep-0389/) 一同发布,是快速创建 Python CLI 应用程序的利器,无需安装如 Typer 或 Click 这样的第三方库。\r\n\r\n`argparse` 模块是作为较旧的 [`getopt`](https://docs.python.org/3/library/getopt.html) 和 [`optparse`](https://docs.python.org/3/library/optparse.html) 模块的替代品而发布的,因为它们缺乏一些重要的功能。\r\n\r\nPython 的 `argparse` 模块允许您: \r\n\r\n- 解析命令行**参数**(arguments)和**选项**(options);\r\n- 在一个单一选项中接受**可变数量的参数**(variable number of parameters);\r\n- 在 CLI 中提供子命令(subcommands)。\r\n\r\n这些特性使 `argparse` 成为了一个强大的 CLI 框架,您在创建 CLI 应用程序时可以放心地依赖它。要使用 Python 的 `argparse`,您需要遵循以下四个简单的步骤:\r\n\r\n1. 导入 `argparse`;\r\n2. 通过实例化 [`ArgumentParser`](https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser) 创建**参数解析器**(argument parser);\r\n3. 使用 [`.add_argument()`](https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.add_argument) 方法向解析器添加**参数**(arguments)和**选项**(options);\r\n4. 在解析器上调用 [`.parse_args()`](https://docs.python.org/3/library/argparse.html?highlight=argparse#argparse.ArgumentParser.parse_args) 以获取参数 [`Namespace`](https://docs.python.org/3/library/argparse.html#namespace)。\r\n\r\n例如,您可以使用 `argparse` 来改进您的 `ls_argv.py` 脚本。现在,您可以创建一个名为 `ls.py` 的脚本,并编写以下代码:\r\n```python\r\n# ls.py v1\r\n\r\nimport argparse\r\nfrom pathlib import Path\r\n\r\nparser = argparse.ArgumentParser()\r\n\r\nparser.add_argument("path")\r\n\r\nargs = parser.parse_args()\r\n\r\ntarget_dir = Path(args.path)\r\n\r\nif not target_dir.exists():\r\n print("The target directory doesn\'t exist")\r\n raise SystemExit(1)\r\n\r\nfor entry in target_dir.iterdir():\r\n print(entry.name)\r\n```\r\n\r\n随着 `argparse` 的引入,您的代码发生了显著的变化。与之前的版本相比,最明显的不同是,用于检查用户提供的参数的条件语句已经消失了。这是因为 `argparse` 会自动为您检查参数的存在性。\r\n\r\n在这个新的实现中,您首先导入 `argparse` 并创建一个参数解析器。要创建解析器,您可以使用 `ArgumentParser` 类。接下来,您定义一个名为 `path` 的参数,用于获取用户的目标目录。\r\n\r\n接下来,您需要调用 `.parse_args()` 方法来解析输入参数,并获取一个包含所有用户参数的 `Namespace` 对象。请注意,现在 `args` 变量保存了一个 `Namespace` 对象,该对象具有从命令行收集的每个参数所对应的属性。\r\n\r\n在这个例子中,您只有一个参数,名为 `path`。`Namespace` 对象允许您使用点表示法通过 `args` 来访问 `path`。其余的代码与第一个实现相同。\r\n\r\n现在继续从命令行运行这个新脚本:\r\n```bash\r\n$ python ls.py sample/\r\nlorem.md\r\nrealpython.md\r\nhello.txt\r\n\r\n$ python ls.py\r\nusage: ls.py [-h] path\r\nls.py: error: the following arguments are required: path\r\n\r\n$ python ls.py sample/ other_dir/\r\nusage: ls.py [-h] path\r\nls.py: error: unrecognized arguments: other_dir/\r\n\r\n$ python ls.py non_existing/\r\nThe target directory doesn\'t exist\r\n```\r\n\r\n第一个命令的输出与您的原始脚本 `ls_argv.py` 相同。而第二个命令的输出则与 `ls_argv.py` 中的输出大不相同。程序现在会显示一个使用说明消息,并发出错误提示,告诉您必须提供 `path` 参数。\r\n\r\n在第三个命令中,您传递了两个目标目录,但应用程序并未为此做好准备。因此,它再次显示使用说明消息,并抛出一个错误,告知您潜在的问题。\r\n\r\n最后,如果您运行脚本时传递了一个不存在的目录作为参数,那么您会收到一个错误,告知您目标目录不存在,因此程序无法执行其工作。\r\n\r\n现在,您可以使用一个新的隐式特性。现在,您的程序接受一个可选的 `-h` 标志。不妨尝试一下:\r\n```bash\r\n$ python ls.py -h\r\nusage: ls.py [-h] path\r\n\r\npositional arguments:\r\n path\r\n\r\noptions:\r\n -h, --help show this help message and exit\r\n```\r\n\r\n太棒了,现在您的程序会自动响应 `-h` 或 `--help` 标志,并为您显示带有使用说明的帮助消息。这真是一个很棒的特性,而且您只需在代码中引入 `argparse` 就能轻松获得!\r\n\r\n经过这个快速介绍如何在 Python 中创建 CLI 应用后,您现在就可以深入研究 `argparse` 模块及其所有炫酷特性了。\r\n\r\n## 使用 Python 的 argparse 创建 CLI\r\n\r\n您可以使用 `argparse` 模块为您的应用程序和项目编写用户友好的命令行界面。该模块允许您定义应用程序所需的参数和选项。然后,`argparse` 将负责为您解析 `sys.argv` 的参数和选项。\r\n\r\n`argparse` 的另一个酷炫特性是它可以自动为您的 CLI 应用程序生成使用说明和帮助消息。该模块还会在参数无效时发出错误提示,并具备更多功能。\r\n\r\n在深入研究 `argparse` 之前,您需要知道该模块的文档可识别两种不同类型的命令行参数: \r\n\r\n- **位置参数**(Positional arguments),您称为参数(arguments);\r\n- **可选参数**(Optional arguments),即选项(options)、标志(flags)或开关(switches)。\r\n\r\n在 `ls.py` 的示例中,`path` 是一个**位置参数**(positional argument)。这样的参数之所以被称为位置参数,是因为它在命令构造中的相对位置定义了其作用。\r\n\r\n与位置参数不同,**可选参数**(Optional arguments)并不是必需的。它们允许你修改命令的行为。以 Unix 命令 `ls` 为例,`-l` 标志就是一个可选参数,它使得命令以详细模式显示输出。\r\n\r\n在明确了这些概念之后,你就可以着手使用 Python 和 `argparse` 库来构建自己的命令行界面(CLI)应用程序了。\r\n\r\n### 创建命令行参数解析器\r\n\r\n命令行参数解析器是任何使用 `argparse` 的命令行界面(CLI)中最为关键的部分。你在命令行上提供的所有参数和选项都会经过这个解析器的处理,它会为你完成繁重的解析工作。\r\n\r\n要使用 `argparse` 创建命令行参数解析器,您需要实例化 [`ArgumentParser`](https://docs.python.org/3/library/argparse.html#argumentparser-objects) 类: \r\n```python\r\n>>> from argparse import ArgumentParser\r\n\r\n>>> parser = ArgumentParser()\r\n>>> parser\r\nArgumentParser(\r\n prog=\'\',\r\n usage=None,\r\n description=None,\r\n formatter_class=,\r\n conflict_handler=\'error\',\r\n add_help=True\r\n)\r\n```\r\n\r\n`ArgumentParser` 的构造函数接受多种不同的参数,你可以利用这些参数来微调你的 CLI 的多个特性。由于所有这些参数都是可选的,因此你可以通过不传入任何参数直接实例化 `ArgumentParser` 来创建一个最基本的解析器。\r\n\r\n在本教程中,你将会更深入地了解 `ArgumentParser` 构造函数的参数,特别是在定制你的参数解析器的部分。目前,你可以开始使用 `argparse` 创建 CLI 的下一步了。这一步就是通过解析器对象来添加参数和选项。\r\n\r\n### 添加参数和选项\r\n\r\n要为 `argparse` 的 CLI 添加参数和选项,你将使用 `ArgumentParser` 实例的 [`.add_argument()`](https://docs.python.org/3/library/argparse.html#the-add-argument-method) 方法。请注意,这个方法对参数和选项都是通用的。在 `argparse` 的术语中,参数被称为**位置参数**(positional arguments),而选项被称为**可选参数**(optional arguments)。\r\n\r\n`.add_argument()` 方法的第一个参数决定了参数和选项之间的区别。这个参数被标识为[名称(name)或标志(flag)](https://docs.python.org/3/library/argparse.html?highlight=argparse#name-or-flags)。因此,如果你提供一个 name,那么你将定义一个参数(argument)。相反,如果你使用一个 flag,那么你将添加一个选项(option)。\r\n\r\n你已经在使用 `argparse` 时处理过命令行参数了。现在,考虑以下你自定义的 `ls` 命令的增强版本,它向 CLI 添加了一个 `-l` 选项: \r\n```python\r\n# ls.py v2\r\n\r\nimport argparse\r\nimport datetime\r\nfrom pathlib import Path\r\n\r\nparser = argparse.ArgumentParser()\r\n\r\nparser.add_argument("path")\r\n\r\nparser.add_argument("-l", "--long", action="store_true")\r\n\r\nargs = parser.parse_args()\r\n\r\ntarget_dir = Path(args.path)\r\n\r\nif not target_dir.exists():\r\n print("The target directory doesn\'t exist")\r\n raise SystemExit(1)\r\n\r\ndef build_output(entry, long=False):\r\n if long:\r\n size = entry.stat().st_size\r\n date = datetime.datetime.fromtimestamp(\r\n entry.stat().st_mtime).strftime(\r\n "%b %d %H:%M:%S"\r\n )\r\n return f"{size:>6d} {date} {entry.name}"\r\n return entry.name\r\n\r\nfor entry in target_dir.iterdir():\r\n print(build_output(entry, long=args.long))\r\n```\r\n\r\n在这个例子中,第 11 行代码创建了一个带有 `-l` 和 `--long` 标志的选项。参数(arguments)和选项(options)在语法上的区别在于,选项名称以短横线 `-` 开头表示简写标志,以双短横线 `--` 开头表示完整标志。\r\n\r\n请注意,在这个特定例子中,与 `-l` 或 `--long` 选项一同设置了一个 `action` 参数为 `"store_true"`,这意味着这个选项将存储一个布尔值。如果你在命令行上提供了这个选项,那么它的值将为 `True`。如果你省略了这个选项,那么它的值将为 `False`。在 "设置 Option 背后的 Action" 部分内容中,你将了解更多关于 `.add_argument()` 中的 `action` 参数的信息。\r\n\r\n在第 21 行的 `build_output()` 函数中,当 `long` 为 `True` 时,它会返回一个详细的输出,否则返回一个简短的输出。详细的输出将包含目标目录中所有条目的大小、修改日期和名称。它使用了诸如 `Path.stat()` 这样的工具,以及带有自定义字符串格式的 `datetime.datetime` 对象。\r\n\r\n继续在 `sample` 上执行您的程序,以检查 `-l` 选项如何工作: \r\n```bash\r\n$ python ls.py -l sample/\r\n 2609 Oct 28 14:07:04 lorem.md\r\n 428 Oct 28 14:07:04 realpython.md\r\n 83 Oct 28 14:07:04 hello.txt\r\n```\r\n\r\n新增的 `-l` 选项允许你生成并显示关于目标目录内容的更详细输出。\r\n\r\n既然你已经知道了如何向 CLI 添加命令行参数和选项,接下来就是深入解析这些参数和选项的时候了。这将是你在接下来部分要探索的内容。\r\n\r\n### 解析命令行参数和选项\r\n\r\n解析命令行参数是基于 `argparse` 的任何 CLI 应用中的另一个重要步骤。一旦你解析了参数,你就可以根据它们的值来执行相应的操作。在你自定义的 `ls` 命令示例中,参数解析发生在包含 `args = parser.parse_args()` 语句的行上。\r\n\r\n这个语句调用了 [`.parse_args()`](https://docs.python.org/3/library/argparse.html#the-parse-args-method) 方法,并将其返回值赋给 `args` 变量。`.parse_args()` 的返回值是一个 [`Namespace`](https://docs.python.org/3/library/argparse.html#the-namespace-object) 对象,其中包含了在命令行上提供的所有参数和选项以及它们对应的值。\r\n\r\n考虑以下简单的示例: \r\n```python\r\n>>> from argparse import ArgumentParser\r\n\r\n>>> parser = ArgumentParser()\r\n\r\n>>> parser.add_argument("site")\r\n_StoreAction(...)\r\n\r\n>>> parser.add_argument("-c", "--connect", action="store_true")\r\n_StoreTrueAction(...)\r\n\r\n>>> args = parser.parse_args(["Real Python", "-c"])\r\n>>> args\r\nNamespace(site=\'Real Python\', connect=True)\r\n\r\n>>> args.site\r\n\'Real Python\'\r\n>>> args.connect\r\nTrue\r\n```\r\n\r\n通过在命令行参数解析器上调用 `.parse_args()` 方法得到的 `Namespace` 对象,你可以使用**点表示法**(dot notation)访问所有输入参数、选项以及它们对应的值。这样,你就可以检查输入参数和选项的列表,并根据用户在命令行上的选择来执行相应的操作。\r\n\r\n你将在应用程序的主代码中使用这个 `Namespace` 对象。这与你在自定义 `ls` 命令示例中的 `for` 循环下所做的类似。\r\n\r\n到目前为止,你已经了解了创建基于 `argparse` 的 CLI 的主要步骤。现在,你可以花些时间学习如何在 Python 中组织和构建 CLI 应用程序的基础知识了。\r\n\r\n### 设置 CLI 应用程序的布局和构建系统\r\n\r\n在继续你的 `argparse` 学习之旅之前,你应该暂停一下,思考如何组织你的代码和规划一个 CLI 项目。首先,你应该考虑以下几点: \r\n\r\n- 你可以创建模块和包来组织代码。\r\n- 你可以将 Python 应用的核心包命名为应用本身的名字。\r\n- 你会根据每个 Python 模块的具体内容或功能来命名它们。\r\n- 如果你希望某个包可以直接执行,你可以在该 Python 包中添加一个 `__main__.py` 模块。\r\n\r\n将这些想法铭记于心,并考虑到模型-视图-控制器(MVC)模式是一种有效组织应用程序结构的方法,你在规划 CLI 项目时可以采用以下目录结构: \r\n```\r\nhello_cli/\r\n│\r\n├── hello_cli/\r\n│ ├── __init__.py\r\n│ ├── __main__.py\r\n│ ├── cli.py\r\n│ └── model.py\r\n│\r\n├── tests/\r\n│ ├── __init__.py\r\n│ ├── test_cli.py\r\n│ └── test_model.py\r\n│\r\n├── pyproject.toml\r\n├── README.md\r\n└── requirements.txt\r\n```\r\n\r\n`hello_cli/` 目录是项目的根目录。在那里,您将放置以下文件: \r\n\r\n- pyproject.toml 是一个 TOML 文件,用于指定项目的构建系统(build system)和其他配置(configurations)。\r\n- README.md 文件提供了项目的描述以及安装和运行应用程序的说明。为你的项目添加一个描述性且详细的 README.md 文件是编程中的最佳实践,特别是如果你打算将项目作为开源解决方案发布的话。\r\n- requirements.txt 是一个常规文件,列出了项目的外部依赖项(external dependencies)。你将使用这个文件,结合 `pip` 的 `-r` 选项,来自动安装这些依赖项。\r\n\r\n接下来是 `hello_cli/` 目录,它包含了应用的核心包,该包包含以下模块: \r\n\r\n- `__init__.py` 文件使得 `hello_cli/` 可以作为一个 Python 包被识别。\r\n- `__main__.py` 文件提供了应用程序的**入口点脚本**(entry-point script)或可执行文件,这是启动程序的主要入口。\r\n- `cli.py` 文件为应用提供了命令行界面。在此文件中的代码将扮演基于 MVC 架构中的视图-控制器角色。\r\n- `model.py` 文件包含了支持应用主要功能的代码。这部分代码将在你的 MVC 布局中扮演模型角色。\r\n\r\n你还需要一个 `tests/` 包,其中包含针对应用程序组件的单元测试文件。在这个具体的项目布局示例中,你有 `test_cli.py` 用于检查 CLI 功能的单元测试,以及 `test_model.py` 用于检查你的模型代码的单元测试。\r\n\r\n`pyproject.toml` 文件允许你定义应用程序的构建系统以及许多其他常规配置。以下是一个如何为你的示例 hello_cli 项目填写此文件的简单示例: \r\n```toml\r\n# pyproject.toml\r\n\r\n[build-system]\r\nrequires = ["setuptools>=64.0.0", "wheel"]\r\nbuild-backend = "setuptools.build_meta"\r\n\r\n[project]\r\nname = "hello_cli"\r\nversion = "0.0.1"\r\ndescription = "My awesome Hello CLI application"\r\nreadme = "README.md"\r\nauthors = [{ name = "Real Python", email = "info@realpython.com" }]\r\n\r\n[project.scripts]\r\nhello_cli = "hello_cli.__main__:main"\r\n```\r\n\r\n`[build-system]` 表头将 `setuptools` 设置为应用程序的构建系统,并指定 Python 需要安装哪些依赖项来构建应用程序。`[project]` 表头为你的应用提供了通用元数据。这些元数据在你想要将应用发布到 Python 包索引(PyPI)时非常有用。最后, `[project.scripts]` 表头定义了你的应用程序的入口点。\r\n\r\n经过这次对 CLI 项目布局和构建的快速探索,你已经准备好继续学习 `argparse` 了,特别是如何自定义你的命令行参数解析器。\r\n\r\n## 自定义你的命令行参数解析器\r\n\r\n在前面的部分中,你已经学习了如何使用 Python 的 `argparse` 模块为你的程序或应用实现命令行接口的基础知识。同时,你也了解了如何按照 MVC 模式组织和规划 CLI 应用项目。\r\n\r\n在接下来的部分中,你将更深入地探索 `argparse` 的许多其他强大功能。特别是,你将学习如何在 `ArgumentParser` 构造函数中使用一些最有用的参数,这将使你能够自定义 CLI 应用的一般行为。\r\n\r\n### 调整程序的 Help 和 Usage 内容\r\n\r\n向 CLI 应用程序的用户提供使用说明和帮助是一种最佳实践,可以通过出色的用户体验 (UX) 让用户更加愉快。在本节中,你将了解如何利用 `ArgumentParser` 的一些参数来微调 CLI 应用程序向用户显示帮助和使用消息的方式。你将学习如何: \r\n- 设置程序名称\r\n- 定义程序的描述和结束消息\r\n- 对参数和选项进行分组显示帮助\r\n\r\n首先,你将开始设置你的程序名称,并指定该名称在帮助或使用说明消息中的显示方式。\r\n\r\n#### 设置程序名称\r\n\r\n默认情况下,`argparse` 会使用 `sys.argv` 中的第一个值来设置程序的名称。这个第一项包含你刚刚执行的 Python 文件的名称。这个文件名在使用说明消息中看起来会有些奇怪。\r\n\r\n例如,继续使用 `-h` 选项运行自定义 `ls` 命令:\r\n```bash\r\n$ python ls.py -h\r\nusage: ls.py [-h] [-l] path\r\n\r\npositional arguments:\r\n path\r\n\r\noptions:\r\n -h, --help show this help message and exit\r\n -l, --long\r\n```\r\n\r\n命令输出中的高亮行显示 `argparse` 正在使用文件名 `ls.py` 作为程序的名称。这看起来有些奇怪,因为在使用说明消息中,应用名称很少包含文件扩展名。\r\n\r\n幸运的是,你可以使用 `prog` 参数来指定你的程序名称,就像下面的代码片段所示: \r\n```python\r\n# ls.py v3\r\n\r\nimport argparse\r\nimport datetime\r\nfrom pathlib import Path\r\n\r\nparser = argparse.ArgumentParser(prog="ls")\r\n\r\n# ...\r\n\r\nfor entry in target_dir.iterdir():\r\n print(build_output(entry, long=args.long))\r\n```\r\n\r\n使用 `prog` 参数,你可以指定将在使用说明消息中使用的程序名称。在这个例子中,你使用了字符串 "ls"。现在,继续运行你的应用: \r\n```bash\r\n$ python ls.py -h\r\nusage: ls [-h] [-l] path\r\n\r\npositional arguments:\r\n path\r\n\r\noptions:\r\n -h, --help show this help message and exit\r\n -l, --long\r\n```\r\n\r\n很好!这个输出的第一行中的使用说明消息显示程序名称为 `ls`,而不是 `ls.py`。\r\n\r\n除了设置程序名称外,`argparse` 还允许你定义应用的描述和结尾信息。在接下来的部分中,你将学习如何进行这两方面的操作。\r\n\r\n#### 定义程序的描述和结语消息\r\n\r\n你还可以为你的应用定义一个通用的描述和一个结尾或结束语。为此,你将分别使用 `description` 和 `epilog` 参数。接下来,请更新 `ls.py` 文件,在 `ArgumentParser` 构造函数中添加以下内容: \r\n```python\r\n# ls.py v4\r\n\r\nimport argparse\r\nimport datetime\r\nfrom pathlib import Path\r\n\r\nparser = argparse.ArgumentParser(\r\n prog="ls",\r\n description="List the content of a directory",\r\n epilog="Thanks for using %(prog)s! :)",\r\n)\r\n\r\n# ...\r\n\r\nfor entry in target_dir.iterdir():\r\n print(build_output(entry, long=args.long))\r\n```\r\n\r\n在这次更新中,`description` 参数允许你为应用提供一个通用的描述。这个描述将显示在帮助消息的开头。`epilog` 参数则允许你定义一些文本作为应用的结尾或结束语。请注意,你可以使用旧式的字符串格式化操作符(`%`)将 `prog` 参数插入到 `epilog` 字符串中。 \r\n\r\n如果再次运行该应用程序,你将得到如下输出: \r\n```bash\r\n$ python ls.py -h\r\nusage: ls [-h] [-l] path\r\n\r\nList the content of a directory\r\n\r\npositional arguments:\r\n path\r\n\r\noptions:\r\n -h, --help show this help message and exit\r\n -l, --long\r\n\r\nThanks for using ls! :)\r\n```\r\n\r\n现在,输出会在使用消息之后显示描述消息,并在帮助文本末尾显示结语消息。\r\n\r\n#### 显示参数和选项的分组帮助\r\n\r\n**帮助分组**(Help groups)是 `argparse` 的另一个有趣特性。它们允许你将相关的命令和参数进行分组,从而帮助你组织应用的帮助消息。要创建这些帮助分组,你将使用 `ArgumentParser` 的 `.add_argument_group()` 方法。\r\n\r\n作为一个例子,请考虑你自定义的 `ls` 命令的以下更新版本: \r\n```python\r\n# ls.py v5\r\n# ...\r\n\r\nparser = argparse.ArgumentParser(\r\n prog="ls",\r\n description="List the content of a directory",\r\n epilog="Thanks for using %(prog)s! :)",\r\n)\r\n\r\ngeneral = parser.add_argument_group("general output")\r\ngeneral.add_argument("path")\r\n\r\ndetailed = parser.add_argument_group("detailed output")\r\ndetailed.add_argument("-l", "--long", action="store_true")\r\n\r\nargs = parser.parse_args()\r\n\r\n# ...\r\n\r\nfor entry in target_dir.iterdir():\r\n print(build_output(entry, long=args.long))\r\n```\r\n\r\n在这次更新中,你为显示一般输出的参数和选项创建了一个帮助分组,并为显示详细输出的参数和选项创建了另一个分组。\r\n\r\n如果你在命令行中使用 `-h` 选项运行应用程序,那么你将获得以下输出: \r\n```bash\r\npython ls.py -h\r\nusage: ls [-h] [-l] path\r\n\r\nList the content of a directory\r\n\r\noptions:\r\n -h, --help show this help message and exit\r\n\r\ngeneral output:\r\n path\r\n\r\ndetailed output:\r\n -l, --long\r\n\r\nThanks for using ls! :)\r\n```\r\n\r\n现在,你的应用的参数和选项在帮助消息中以描述性的标题进行了方便的分组。这个整洁的特性将帮助你为用户提供更多的上下文,并帮助他们更好地理解应用的工作原理。\r\n\r\n### 为参数和选项提供全局设置\r\n\r\n除了自定义使用说明和帮助消息外,`ArgumentParser` 还允许你对命令行界面(CLI)应用进行其他一些有趣的调整。这些调整包括:\r\n\r\n- 为参数和选项定义全局默认值\r\n- 从外部文件中加载参数和选项\r\n- 允许或禁止选项缩写\r\n\r\n有时,你可能需要为你的应用的参数和选项指定一个全局默认值。你可以通过在调用 `ArgumentParser` 构造函数时,将默认值传递给 `argument_default` 参数来实现这一点(注意:实际上 `ArgumentParser` 没有 `argument_default` 这个参数,但这里是为了说明可以全局设置默认值的概念。在实际应用中,你可能需要为每个参数单独设置默认值)。\r\n\r\n这个特性可能并不常用,因为参数和选项通常具有不同的数据类型或意义,很难找到一个满足所有需求的值。\r\n\r\n然而,`argument_default`(尽管 `ArgumentParser` 并没有直接提供这个参数,但这里是为了说明概念)的一个常见用例是当你想要避免将参数和选项添加到 `Namespace` 对象中。在这种情况下,你可以使用 `SUPPRESS` 常量作为默认值。这个默认值将确保只有命令行中提供的参数和选项才会被存储在 `arguments` 的 `Namespace` 中。\r\n\r\n作为一个例子,请继续修改你的自定义 `ls` 命令,如下面的代码片段所示: \r\n```python\r\n# ls.py v6\r\n\r\nimport argparse\r\nimport datetime\r\nfrom pathlib import Path\r\n\r\nparser = argparse.ArgumentParser(\r\n prog="ls",\r\n description="List the content of a directory",\r\n epilog="Thanks for using %(prog)s! :)",\r\n argument_default=argparse.SUPPRESS,\r\n)\r\n\r\n# ...\r\n\r\nfor entry in target_dir.iterdir():\r\n try:\r\n long = args.long\r\n except AttributeError:\r\n long = False\r\n print(build_output(entry, long=long))\r\n```\r\n\r\n通过将 `SUPPRESS` 传递给 `ArgumentParser` 构造函数,你可以防止未提供的参数被存储在 `argparse.Namespace` 对象中。这就是为什么在调用 `build_output()` 之前,你需要检查 `-l` 或 `--long` 选项是否实际被传递了。否则,你的代码会因为 `args` 中不存在 `long` 属性而引发 `AttributeError` 错误。\r\n\r\n`ArgumentParser` 的另一个酷炫功能是允许你从外部文件中加载参数值。当你有一个具有冗长或复杂的命令行结构的应用,并希望自动化加载参数值的过程时,这个功能就非常有用。\r\n\r\n在这种情况下,你可以将参数值存储在一个外部文件中,并让你的程序从该文件中加载它们。为了尝试这个功能,请继续创建一个简单的命令行界面(CLI)应用,如下所示: \r\n```python\r\n# fromfile.py\r\n\r\nimport argparse\r\n\r\nparser = argparse.ArgumentParser(fromfile_prefix_chars="@")\r\n\r\nparser.add_argument("one")\r\nparser.add_argument("two")\r\nparser.add_argument("three")\r\n\r\nargs = parser.parse_args()\r\n\r\nprint(args)\r\n```\r\n\r\n在这里,你向 `ArgumentParser` 的 `fromfile_prefix_chars` 参数传递 `@` 符号。然后,你创建了三个必须在命令行中提供的必需参数。\r\n\r\n现在,假设你经常使用此应用程序,并且总是使用相同的一组参数值。为了简化和优化你的工作流程,你可以创建一个文件,其中包含所有必需参数的适当值,每个参数占一行,就像下面的 `args.txt` 文件一样: \r\n```\r\nfirst\r\nsecond\r\nthird\r\n```\r\n\r\n有了这个文件,您现在可以调用您的程序并指示它从 `args.txt` 文件加载值,如以下命令运行所示: \r\n```bash\r\n$ python fromfile.py @args.txt\r\nNamespace(one=\'first\', two=\'second\', three=\'third\')\r\n```\r\n\r\n在此命令的输出中,你可以看到 `argparse` 已经读取了 `args.txt` 的内容,并顺序地将值分配给了 `fromfile.py` 程序的每个参数。所有参数及其值都已成功存储在 `Namespace` 对象中。\r\n\r\n接受缩写选项名称的能力是 `argparse` 命令行界面(CLI)的另一个酷炫特性。这个特性是默认启用的,当你的程序具有长选项名称时非常有用。例如,考虑以下程序,它会在命令行下打印出你在 `--argument-with-a-long-name` 选项后指定的值: \r\n```python\r\n# abbreviate.py\r\n\r\nimport argparse\r\n\r\nparser = argparse.ArgumentParser()\r\n\r\nparser.add_argument("--argument-with-a-long-name")\r\n\r\nargs = parser.parse_args()\r\n\r\nprint(args.argument_with_a_long_name)\r\n```\r\n\r\n这个程序会打印出你在 `--argument-with-a-long-name` 选项后传入的任何参数值。现在,请继续运行以下命令来检查 Python 的 `argparse` 模块如何处理这些缩写: \r\n```bash\r\n$ python abbreviate.py --argument-with-a-long-name 42\r\n42\r\n\r\n$ python abbreviate.py --argument 42\r\n42\r\n\r\n$ python abbreviate.py --a 42\r\n42\r\n```\r\n\r\n这些示例展示了如何缩写 `--argument-with-a-long-name` 选项的名称,而应用程序仍能正常工作。此功能是默认启用的。如果你希望禁用它并禁止缩写,那么可以在 `ArgumentParser` 中使用 `allow_abbrev` 参数: \r\n```python\r\n# abbreviate.py\r\n\r\nimport argparse\r\n\r\nparser = argparse.ArgumentParser(allow_abbrev=False)\r\n\r\nparser.add_argument("--argument-with-a-long-name")\r\n\r\nargs = parser.parse_args()\r\n\r\nprint(args.argument_with_a_long_name)\r\n```\r\n\r\n将 `allow_abbrev` 设置为 `False` 会禁用命令行选项中的缩写。从这一点开始,你将需要为程序提供完整的选项名称才能正确工作。否则,你会收到一个错误: \r\n```bash\r\n$ python abbreviate.py --argument-with-a-long-name 42\r\n42\r\n\r\n$ python abbreviate.py --argument 42\r\nusage: abbreviate.py [-h] [--argument-with-a-long-name ...]\r\nabbreviate.py: error: unrecognized arguments: --argument 42\r\n```\r\n\r\n第二个示例中的错误消息告诉你 `--argument` 选项没有被识别为有效的选项。要使用该选项,你需要提供它的完整名称。\r\n\r\n## 微调你的命令行参数和选项\r\n\r\n到目前为止,你已经学习了如何定制 `ArgumentParser` 类的多个功能,以改善你的命令行界面(CLI)的用户体验。现在,你知道了如何调整你的应用程序的使用说明和帮助信息,以及如何微调命令行参数和选项的一些全局方面。\r\n\r\n在本节中,你将学习如何定制你的 CLI 的命令行参数和选项的其他几个功能。在这种情况下,你将使用 `.add_argument()` 方法及其一些最相关的参数,包括 `action`、`type`、`nargs`、`default`、`help` 等。 \r\n\r\n### 设置 Option 背后的 Action\r\n\r\n当你向命令行界面添加一个选项或标志时,通常需要定义如何将选项的值存储在调用 `.parse_args()` 后得到的 `Namespace` 对象中。为此,你会使用 `.add_argument()` 的 `action` 参数。`action` 参数的默认值为 "store",意味着提供的选项值将原样存储在 `Namespace` 中。\r\n\r\n`action` 参数可以接受几个可能的值。以下是这些可能值的列表及其含义:', 'bodyText': '原文:Build Command-Line Interfaces With Python\'s argparse\n\n命令行应用在普通用户空间中可能并不常见,但它们存在于开发、数据科学、系统管理和许多其他操作中。每个命令行应用都需要一个用户友好的命令行界面 (CLI),以便你可以与应用本身进行交互。在 Python 中,您可以使用标准库中的 argparse 模块创建功能齐全的 CLI。\n\n在本文中,你将了解如何:\n\n命令行界面入门;\n在 Python 中组织和布局命令行应用项目;\n使用 Python argparse 创建命令行界面(command-line interfaces);\n使用 argparse 一些强大的功能深度自定义您的 CLI;\n\n若要充分利用本教程,应熟悉 Python 编程,包括面向对象编程、脚本开发和执行以及 Python 包和模块等概念。如果您熟悉与使用命令行或终端相关的一般概念和主题,这也将很有帮助。\n了解命令行界面\n自从计算机发明以来,人类一直需要并找到与这些机器交互和共享信息的方法。信息交换在人、计算机软件和硬件组件之间流动。其中任意两个元素之间的共享边界通常称为接口(interface)。\n在软件开发中,接口是给定软件的特殊部分,它允许计算机系统组件之间的交互。当涉及到人机交互和软件交互时,这个重要的组件被称为用户界面(user interface)。\n您会在编程中找到不同类型的用户界面。图形用户界面 (GUI) 可能是当今最常见的。但是,您还可以找到为其用户提供命令行界面 (CLI) 的应用和程序。在本教程中,你将了解 CLI 以及如何在 Python 中创建它们。\n命令行界面 (CLI)\n命令行界面允许您通过操作系统命令行、终端或控制台与应用程序或程序进行交互。\n要了解命令行界面及其工作原理,请考虑此实际示例。假设您有一个名为 sample 包含三个示例文件的目录。如果您使用的是类 Unix 操作系统,例如 Linux 或 macOS,请继续在父目录中打开命令行窗口或终端,然后执行以下命令:\n$ ls sample/\nhello.txt lorem.md realpython.md\nUnix 的 ls 命令列出目标目录中包含的文件和子目录,该目录默认为当前工作目录。上面的命令调用没有显示有关 的内容 sample 的太多信息。它只在屏幕上显示文件名。\n假设你想要获取有关目录及其内容的更丰富信息,那么你不需要寻找其他程序,因为 ls 命令有一个功能齐全的命令行界面,并且提供了一组有用的选项,可以用来定制命令的行为。\n例如,继续执行带有 -l 选项的 ls 命令:\n$ ls -l sample/\ntotal 24\n-rw-r--r--@ 1 user staff 83 Aug 17 22:15 hello.txt\n-rw-r--r--@ 1 user staff 2609 Aug 17 22:15 lorem.md\n-rw-r--r--@ 1 user staff 428 Aug 17 22:15 realpython.md\n现在,ls 命令的输出完全不同了。该命令显示了有关 sample 目录中文件的更多信息,包括权限、所有者、组、日期和大小。它还显示了这些文件在你计算机磁盘上使用的总空间。\n这种更丰富的输出结果是由于使用了 -l 选项,这是 Unix ls 命令行界面的一部分,它启用了详细的输出格式。\n命令、参数、选项、参数和子命令\n在本教程中,您将深入了解命令(commands)及其子命令(subcommands),同时还会学习到命令行参数(command-line arguments)、选项(options)和参数(parameters)的相关知识。因此,建议您将这些术语纳入您的技术词汇库中。\n\n命令(Command):在命令行或终端窗口中运行的程序或例程。通常,您可以通过其背后的程序(underlying program)或例程(routine)的名称来识别一个命令。\n参数(Argument):命令在执行其预期操作时所需或可选的信息片段。命令通常接受一个或多个参数,您可以在命令行中以空格分隔或逗号分隔的列表形式提供这些参数。\n选项(Option),也称为 flag 或 switch:一种可选的参数,用于修改命令的行为。选项通过特定的名称(如前一个示例中的 -l)传递给命令。\n参数(Parameter):一个选项用于执行其预期操作或动作时所使用的参数。\n子命令(Subcommand)**:一个预定义的名称,可以传递给应用程序来执行特定的操作。\n\n参考上一节中的示例命令结构:\n$ ls -l sample/\n在这个例子中,您组合了命令行界面(CLI)的以下组件:\n\nls:命令的名称或应用的名称;\n-l:启用详细输出的选项(option)、开关(switch)或标志(flag);\nsample:为命令执行提供附加信息的参数(argument);\n\n现在,让我们来看下面的命令结构,它展示了 Python 包管理器 pip 的命令行界面(CLI):\n$ pip install -r requirements.txt\n这是一个常见的 pip 命令结构,您可能之前已经见过。它允许您使用 requirements.txt 文件来给指定的 Python 项目安装依赖项。在这个例子中,您使用了以下命令行界面(CLI)组件:\n\npip:命令的名称;\ninstall:pip 的子命令(subcommand)名称;\n-r:install 子命令的选项(option);\nrequirements.txt:一个参数,特别是 -r 选项的参数。\n\n现在您已经了解了命令行界面(CLI)是什么以及其主要部分或组件有哪些。接下来,是时候学习如何在 Python 中创建自己的 CLI 了。\nPython 中的 CLI 入门\nPython 附带了一些工具,这些工具可帮助您为程序和应用程序编写命令行界面(CLI)。若您需要快速为小型程序构建一个简洁的 CLI,那么可以利用 sys 模块中的 argv 属性。这个属性会自动存储您在命令行中传递给特定程序的参数。\n使用 sys.argv 构建最小的 CLI\n以使用 argv 创建最小命令行界面(CLI)为例,假设您需要编写一个小程序,该程序类似于 ls 命令,能够列出给定目录下的所有文件。在这种情况下,您可以编写如下代码:\n# ls_argv.py\n\nimport sys\nfrom pathlib import Path\n\nif (args_count := len(sys.argv)) > 2:\n print(f"One argument expected, got {args_count - 1}")\n raise SystemExit(2)\nelif args_count < 2:\n print("You must specify the target directory")\n raise SystemExit(2)\n\ntarget_dir = Path(sys.argv[1])\n\nif not target_dir.is_dir():\n print("The target directory doesn\'t exist")\n raise SystemExit(1)\n\nfor entry in target_dir.iterdir():\n print(entry.name)\n该程序通过手动处理命令行提供的参数来实现了一个简单的命令行界面(CLI),这些参数会自动存储在 sys.argv 中。sys.argv 的第一个元素始终是程序名称,第二个元素则是目标目录。由于应用程序不应接受超过一个目标目录,因此 args_count 不得超过 2。\n在检查 sys.argv 的内容后,您创建一个pathlib.Path对象来存储目标目录的路径。如果该目录不存在,您将通知用户并退出程序。接下来的for循环将列出目录内容,每行一个条目。\n如果从命令行运行该脚本,您将得到以下结果:\n$ python ls_argv.py sample/\nhello.txt\nlorem.md\nrealpython.md\n\n$ python ls_argv.py\nYou must specify the target directory\n\n$ python ls_argv.py sample/ other_dir/\nOne argument expected, got 2\n\n$ python ls_argv.py non_existing/\nThe target directory doesn\'t exist\n您的程序接受一个目录作为参数,并列出其内容。如果您运行命令时没有提供参数,您将收到一个错误消息。如果您运行命令时指定了超过一个目标目录,您同样会收到一个错误消息。如果尝试运行命令并指定一个不存在的目录,程序将输出另一个错误消息。\n虽然您的程序运行正常,但对于更复杂的 CLI 应用程序来说,使用sys.argv属性手动解析命令行参数并不是一个可扩展的解决方案。如果您的应用需要接受更多的参数和选项,那么解析sys.argv将变得复杂且容易出错。您需要一个更好的解决方案,这就是 Python 中的argparse模块所提供的。\n使用 argparse 创建 CLI\n在 Python 中创建 CLI 应用程序的更便捷方法是使用标准库中的 argparse 模块。该模块首次在 Python 3.2 中随 PEP-389 一同发布,是快速创建 Python CLI 应用程序的利器,无需安装如 Typer 或 Click 这样的第三方库。\nargparse 模块是作为较旧的 getopt 和 optparse 模块的替代品而发布的,因为它们缺乏一些重要的功能。\nPython 的 argparse 模块允许您:\n\n解析命令行参数(arguments)和选项(options);\n在一个单一选项中接受可变数量的参数(variable number of parameters);\n在 CLI 中提供子命令(subcommands)。\n\n这些特性使 argparse 成为了一个强大的 CLI 框架,您在创建 CLI 应用程序时可以放心地依赖它。要使用 Python 的 argparse,您需要遵循以下四个简单的步骤:\n\n导入 argparse;\n通过实例化 ArgumentParser 创建参数解析器(argument parser);\n使用 .add_argument() 方法向解析器添加参数(arguments)和选项(options);\n在解析器上调用 .parse_args() 以获取参数 Namespace。\n\n例如,您可以使用 argparse 来改进您的 ls_argv.py 脚本。现在,您可以创建一个名为 ls.py 的脚本,并编写以下代码:\n# ls.py v1\n\nimport argparse\nfrom pathlib import Path\n\nparser = argparse.ArgumentParser()\n\nparser.add_argument("path")\n\nargs = parser.parse_args()\n\ntarget_dir = Path(args.path)\n\nif not target_dir.exists():\n print("The target directory doesn\'t exist")\n raise SystemExit(1)\n\nfor entry in target_dir.iterdir():\n print(entry.name)\n随着 argparse 的引入,您的代码发生了显著的变化。与之前的版本相比,最明显的不同是,用于检查用户提供的参数的条件语句已经消失了。这是因为 argparse 会自动为您检查参数的存在性。\n在这个新的实现中,您首先导入 argparse 并创建一个参数解析器。要创建解析器,您可以使用 ArgumentParser 类。接下来,您定义一个名为 path 的参数,用于获取用户的目标目录。\n接下来,您需要调用 .parse_args() 方法来解析输入参数,并获取一个包含所有用户参数的 Namespace 对象。请注意,现在 args 变量保存了一个 Namespace 对象,该对象具有从命令行收集的每个参数所对应的属性。\n在这个例子中,您只有一个参数,名为 path。Namespace 对象允许您使用点表示法通过 args 来访问 path。其余的代码与第一个实现相同。\n现在继续从命令行运行这个新脚本:\n$ python ls.py sample/\nlorem.md\nrealpython.md\nhello.txt\n\n$ python ls.py\nusage: ls.py [-h] path\nls.py: error: the following arguments are required: path\n\n$ python ls.py sample/ other_dir/\nusage: ls.py [-h] path\nls.py: error: unrecognized arguments: other_dir/\n\n$ python ls.py non_existing/\nThe target directory doesn\'t exist\n第一个命令的输出与您的原始脚本 ls_argv.py 相同。而第二个命令的输出则与 ls_argv.py 中的输出大不相同。程序现在会显示一个使用说明消息,并发出错误提示,告诉您必须提供 path 参数。\n在第三个命令中,您传递了两个目标目录,但应用程序并未为此做好准备。因此,它再次显示使用说明消息,并抛出一个错误,告知您潜在的问题。\n最后,如果您运行脚本时传递了一个不存在的目录作为参数,那么您会收到一个错误,告知您目标目录不存在,因此程序无法执行其工作。\n现在,您可以使用一个新的隐式特性。现在,您的程序接受一个可选的 -h 标志。不妨尝试一下:\n$ python ls.py -h\nusage: ls.py [-h] path\n\npositional arguments:\n path\n\noptions:\n -h, --help show this help message and exit\n太棒了,现在您的程序会自动响应 -h 或 --help 标志,并为您显示带有使用说明的帮助消息。这真是一个很棒的特性,而且您只需在代码中引入 argparse 就能轻松获得!\n经过这个快速介绍如何在 Python 中创建 CLI 应用后,您现在就可以深入研究 argparse 模块及其所有炫酷特性了。\n使用 Python 的 argparse 创建 CLI\n您可以使用 argparse 模块为您的应用程序和项目编写用户友好的命令行界面。该模块允许您定义应用程序所需的参数和选项。然后,argparse 将负责为您解析 sys.argv 的参数和选项。\nargparse 的另一个酷炫特性是它可以自动为您的 CLI 应用程序生成使用说明和帮助消息。该模块还会在参数无效时发出错误提示,并具备更多功能。\n在深入研究 argparse 之前,您需要知道该模块的文档可识别两种不同类型的命令行参数:\n\n位置参数(Positional arguments),您称为参数(arguments);\n可选参数(Optional arguments),即选项(options)、标志(flags)或开关(switches)。\n\n在 ls.py 的示例中,path 是一个位置参数(positional argument)。这样的参数之所以被称为位置参数,是因为它在命令构造中的相对位置定义了其作用。\n与位置参数不同,可选参数(Optional arguments)并不是必需的。它们允许你修改命令的行为。以 Unix 命令 ls 为例,-l 标志就是一个可选参数,它使得命令以详细模式显示输出。\n在明确了这些概念之后,你就可以着手使用 Python 和 argparse 库来构建自己的命令行界面(CLI)应用程序了。\n创建命令行参数解析器\n命令行参数解析器是任何使用 argparse 的命令行界面(CLI)中最为关键的部分。你在命令行上提供的所有参数和选项都会经过这个解析器的处理,它会为你完成繁重的解析工作。\n要使用 argparse 创建命令行参数解析器,您需要实例化 ArgumentParser 类:\n>>> from argparse import ArgumentParser\n\n>>> parser = ArgumentParser()\n>>> parser\nArgumentParser(\n prog=\'\',\n usage=None,\n description=None,\n formatter_class=,\n conflict_handler=\'error\',\n add_help=True\n)\nArgumentParser 的构造函数接受多种不同的参数,你可以利用这些参数来微调你的 CLI 的多个特性。由于所有这些参数都是可选的,因此你可以通过不传入任何参数直接实例化 ArgumentParser 来创建一个最基本的解析器。\n在本教程中,你将会更深入地了解 ArgumentParser 构造函数的参数,特别是在定制你的参数解析器的部分。目前,你可以开始使用 argparse 创建 CLI 的下一步了。这一步就是通过解析器对象来添加参数和选项。\n添加参数和选项\n要为 argparse 的 CLI 添加参数和选项,你将使用 ArgumentParser 实例的 .add_argument() 方法。请注意,这个方法对参数和选项都是通用的。在 argparse 的术语中,参数被称为位置参数(positional arguments),而选项被称为可选参数(optional arguments)。\n.add_argument() 方法的第一个参数决定了参数和选项之间的区别。这个参数被标识为名称(name)或标志(flag)。因此,如果你提供一个 name,那么你将定义一个参数(argument)。相反,如果你使用一个 flag,那么你将添加一个选项(option)。\n你已经在使用 argparse 时处理过命令行参数了。现在,考虑以下你自定义的 ls 命令的增强版本,它向 CLI 添加了一个 -l 选项:\n# ls.py v2\n\nimport argparse\nimport datetime\nfrom pathlib import Path\n\nparser = argparse.ArgumentParser()\n\nparser.add_argument("path")\n\nparser.add_argument("-l", "--long", action="store_true")\n\nargs = parser.parse_args()\n\ntarget_dir = Path(args.path)\n\nif not target_dir.exists():\n print("The target directory doesn\'t exist")\n raise SystemExit(1)\n\ndef build_output(entry, long=False):\n if long:\n size = entry.stat().st_size\n date = datetime.datetime.fromtimestamp(\n entry.stat().st_mtime).strftime(\n "%b %d %H:%M:%S"\n )\n return f"{size:>6d} {date} {entry.name}"\n return entry.name\n\nfor entry in target_dir.iterdir():\n print(build_output(entry, long=args.long))\n在这个例子中,第 11 行代码创建了一个带有 -l 和 --long 标志的选项。参数(arguments)和选项(options)在语法上的区别在于,选项名称以短横线 - 开头表示简写标志,以双短横线 -- 开头表示完整标志。\n请注意,在这个特定例子中,与 -l 或 --long 选项一同设置了一个 action 参数为 "store_true",这意味着这个选项将存储一个布尔值。如果你在命令行上提供了这个选项,那么它的值将为 True。如果你省略了这个选项,那么它的值将为 False。在 "设置 Option 背后的 Action" 部分内容中,你将了解更多关于 .add_argument() 中的 action 参数的信息。\n在第 21 行的 build_output() 函数中,当 long 为 True 时,它会返回一个详细的输出,否则返回一个简短的输出。详细的输出将包含目标目录中所有条目的大小、修改日期和名称。它使用了诸如 Path.stat() 这样的工具,以及带有自定义字符串格式的 datetime.datetime 对象。\n继续在 sample 上执行您的程序,以检查 -l 选项如何工作:\n$ python ls.py -l sample/\n 2609 Oct 28 14:07:04 lorem.md\n 428 Oct 28 14:07:04 realpython.md\n 83 Oct 28 14:07:04 hello.txt\n新增的 -l 选项允许你生成并显示关于目标目录内容的更详细输出。\n既然你已经知道了如何向 CLI 添加命令行参数和选项,接下来就是深入解析这些参数和选项的时候了。这将是你在接下来部分要探索的内容。\n解析命令行参数和选项\n解析命令行参数是基于 argparse 的任何 CLI 应用中的另一个重要步骤。一旦你解析了参数,你就可以根据它们的值来执行相应的操作。在你自定义的 ls 命令示例中,参数解析发生在包含 args = parser.parse_args() 语句的行上。\n这个语句调用了 .parse_args() 方法,并将其返回值赋给 args 变量。.parse_args() 的返回值是一个 Namespace 对象,其中包含了在命令行上提供的所有参数和选项以及它们对应的值。\n考虑以下简单的示例:\n>>> from argparse import ArgumentParser\n\n>>> parser = ArgumentParser()\n\n>>> parser.add_argument("site")\n_StoreAction(...)\n\n>>> parser.add_argument("-c", "--connect", action="store_true")\n_StoreTrueAction(...)\n\n>>> args = parser.parse_args(["Real Python", "-c"])\n>>> args\nNamespace(site=\'Real Python\', connect=True)\n\n>>> args.site\n\'Real Python\'\n>>> args.connect\nTrue\n通过在命令行参数解析器上调用 .parse_args() 方法得到的 Namespace 对象,你可以使用点表示法(dot notation)访问所有输入参数、选项以及它们对应的值。这样,你就可以检查输入参数和选项的列表,并根据用户在命令行上的选择来执行相应的操作。\n你将在应用程序的主代码中使用这个 Namespace 对象。这与你在自定义 ls 命令示例中的 for 循环下所做的类似。\n到目前为止,你已经了解了创建基于 argparse 的 CLI 的主要步骤。现在,你可以花些时间学习如何在 Python 中组织和构建 CLI 应用程序的基础知识了。\n设置 CLI 应用程序的布局和构建系统\n在继续你的 argparse 学习之旅之前,你应该暂停一下,思考如何组织你的代码和规划一个 CLI 项目。首先,你应该考虑以下几点:\n\n你可以创建模块和包来组织代码。\n你可以将 Python 应用的核心包命名为应用本身的名字。\n你会根据每个 Python 模块的具体内容或功能来命名它们。\n如果你希望某个包可以直接执行,你可以在该 Python 包中添加一个 __main__.py 模块。\n\n将这些想法铭记于心,并考虑到模型-视图-控制器(MVC)模式是一种有效组织应用程序结构的方法,你在规划 CLI 项目时可以采用以下目录结构:\nhello_cli/\n│\n├── hello_cli/\n│ ├── __init__.py\n│ ├── __main__.py\n│ ├── cli.py\n│ └── model.py\n│\n├── tests/\n│ ├── __init__.py\n│ ├── test_cli.py\n│ └── test_model.py\n│\n├── pyproject.toml\n├── README.md\n└── requirements.txt\n\nhello_cli/ 目录是项目的根目录。在那里,您将放置以下文件:\n\npyproject.toml 是一个 TOML 文件,用于指定项目的构建系统(build system)和其他配置(configurations)。\nREADME.md 文件提供了项目的描述以及安装和运行应用程序的说明。为你的项目添加一个描述性且详细的 README.md 文件是编程中的最佳实践,特别是如果你打算将项目作为开源解决方案发布的话。\nrequirements.txt 是一个常规文件,列出了项目的外部依赖项(external dependencies)。你将使用这个文件,结合 pip 的 -r 选项,来自动安装这些依赖项。\n\n接下来是 hello_cli/ 目录,它包含了应用的核心包,该包包含以下模块:\n\n__init__.py 文件使得 hello_cli/ 可以作为一个 Python 包被识别。\n__main__.py 文件提供了应用程序的入口点脚本(entry-point script)或可执行文件,这是启动程序的主要入口。\ncli.py 文件为应用提供了命令行界面。在此文件中的代码将扮演基于 MVC 架构中的视图-控制器角色。\nmodel.py 文件包含了支持应用主要功能的代码。这部分代码将在你的 MVC 布局中扮演模型角色。\n\n你还需要一个 tests/ 包,其中包含针对应用程序组件的单元测试文件。在这个具体的项目布局示例中,你有 test_cli.py 用于检查 CLI 功能的单元测试,以及 test_model.py 用于检查你的模型代码的单元测试。\npyproject.toml 文件允许你定义应用程序的构建系统以及许多其他常规配置。以下是一个如何为你的示例 hello_cli 项目填写此文件的简单示例:\n# pyproject.toml\n\n[build-system]\nrequires = ["setuptools>=64.0.0", "wheel"]\nbuild-backend = "setuptools.build_meta"\n\n[project]\nname = "hello_cli"\nversion = "0.0.1"\ndescription = "My awesome Hello CLI application"\nreadme = "README.md"\nauthors = [{ name = "Real Python", email = "info@realpython.com" }]\n\n[project.scripts]\nhello_cli = "hello_cli.__main__:main"\n[build-system] 表头将 setuptools 设置为应用程序的构建系统,并指定 Python 需要安装哪些依赖项来构建应用程序。[project] 表头为你的应用提供了通用元数据。这些元数据在你想要将应用发布到 Python 包索引(PyPI)时非常有用。最后, [project.scripts] 表头定义了你的应用程序的入口点。\n经过这次对 CLI 项目布局和构建的快速探索,你已经准备好继续学习 argparse 了,特别是如何自定义你的命令行参数解析器。\n自定义你的命令行参数解析器\n在前面的部分中,你已经学习了如何使用 Python 的 argparse 模块为你的程序或应用实现命令行接口的基础知识。同时,你也了解了如何按照 MVC 模式组织和规划 CLI 应用项目。\n在接下来的部分中,你将更深入地探索 argparse 的许多其他强大功能。特别是,你将学习如何在 ArgumentParser 构造函数中使用一些最有用的参数,这将使你能够自定义 CLI 应用的一般行为。\n调整程序的 Help 和 Usage 内容\n向 CLI 应用程序的用户提供使用说明和帮助是一种最佳实践,可以通过出色的用户体验 (UX) 让用户更加愉快。在本节中,你将了解如何利用 ArgumentParser 的一些参数来微调 CLI 应用程序向用户显示帮助和使用消息的方式。你将学习如何:\n\n设置程序名称\n定义程序的描述和结束消息\n对参数和选项进行分组显示帮助\n\n首先,你将开始设置你的程序名称,并指定该名称在帮助或使用说明消息中的显示方式。\n设置程序名称\n默认情况下,argparse 会使用 sys.argv 中的第一个值来设置程序的名称。这个第一项包含你刚刚执行的 Python 文件的名称。这个文件名在使用说明消息中看起来会有些奇怪。\n例如,继续使用 -h 选项运行自定义 ls 命令:\n$ python ls.py -h\nusage: ls.py [-h] [-l] path\n\npositional arguments:\n path\n\noptions:\n -h, --help show this help message and exit\n -l, --long\n命令输出中的高亮行显示 argparse 正在使用文件名 ls.py 作为程序的名称。这看起来有些奇怪,因为在使用说明消息中,应用名称很少包含文件扩展名。\n幸运的是,你可以使用 prog 参数来指定你的程序名称,就像下面的代码片段所示:\n# ls.py v3\n\nimport argparse\nimport datetime\nfrom pathlib import Path\n\nparser = argparse.ArgumentParser(prog="ls")\n\n# ...\n\nfor entry in target_dir.iterdir():\n print(build_output(entry, long=args.long))\n使用 prog 参数,你可以指定将在使用说明消息中使用的程序名称。在这个例子中,你使用了字符串 "ls"。现在,继续运行你的应用:\n$ python ls.py -h\nusage: ls [-h] [-l] path\n\npositional arguments:\n path\n\noptions:\n -h, --help show this help message and exit\n -l, --long\n很好!这个输出的第一行中的使用说明消息显示程序名称为 ls,而不是 ls.py。\n除了设置程序名称外,argparse 还允许你定义应用的描述和结尾信息。在接下来的部分中,你将学习如何进行这两方面的操作。\n定义程序的描述和结语消息\n你还可以为你的应用定义一个通用的描述和一个结尾或结束语。为此,你将分别使用 description 和 epilog 参数。接下来,请更新 ls.py 文件,在 ArgumentParser 构造函数中添加以下内容:\n# ls.py v4\n\nimport argparse\nimport datetime\nfrom pathlib import Path\n\nparser = argparse.ArgumentParser(\n prog="ls",\n description="List the content of a directory",\n epilog="Thanks for using %(prog)s! :)",\n)\n\n# ...\n\nfor entry in target_dir.iterdir():\n print(build_output(entry, long=args.long))\n在这次更新中,description 参数允许你为应用提供一个通用的描述。这个描述将显示在帮助消息的开头。epilog 参数则允许你定义一些文本作为应用的结尾或结束语。请注意,你可以使用旧式的字符串格式化操作符(%)将 prog 参数插入到 epilog 字符串中。\n如果再次运行该应用程序,你将得到如下输出:\n$ python ls.py -h\nusage: ls [-h] [-l] path\n\nList the content of a directory\n\npositional arguments:\n path\n\noptions:\n -h, --help show this help message and exit\n -l, --long\n\nThanks for using ls! :)\n现在,输出会在使用消息之后显示描述消息,并在帮助文本末尾显示结语消息。\n显示参数和选项的分组帮助\n帮助分组(Help groups)是 argparse 的另一个有趣特性。它们允许你将相关的命令和参数进行分组,从而帮助你组织应用的帮助消息。要创建这些帮助分组,你将使用 ArgumentParser 的 .add_argument_group() 方法。\n作为一个例子,请考虑你自定义的 ls 命令的以下更新版本:\n# ls.py v5\n# ...\n\nparser = argparse.ArgumentParser(\n prog="ls",\n description="List the content of a directory",\n epilog="Thanks for using %(prog)s! :)",\n)\n\ngeneral = parser.add_argument_group("general output")\ngeneral.add_argument("path")\n\ndetailed = parser.add_argument_group("detailed output")\ndetailed.add_argument("-l", "--long", action="store_true")\n\nargs = parser.parse_args()\n\n# ...\n\nfor entry in target_dir.iterdir():\n print(build_output(entry, long=args.long))\n在这次更新中,你为显示一般输出的参数和选项创建了一个帮助分组,并为显示详细输出的参数和选项创建了另一个分组。\n如果你在命令行中使用 -h 选项运行应用程序,那么你将获得以下输出:\npython ls.py -h\nusage: ls [-h] [-l] path\n\nList the content of a directory\n\noptions:\n -h, --help show this help message and exit\n\ngeneral output:\n path\n\ndetailed output:\n -l, --long\n\nThanks for using ls! :)\n现在,你的应用的参数和选项在帮助消息中以描述性的标题进行了方便的分组。这个整洁的特性将帮助你为用户提供更多的上下文,并帮助他们更好地理解应用的工作原理。\n为参数和选项提供全局设置\n除了自定义使用说明和帮助消息外,ArgumentParser 还允许你对命令行界面(CLI)应用进行其他一些有趣的调整。这些调整包括:\n\n为参数和选项定义全局默认值\n从外部文件中加载参数和选项\n允许或禁止选项缩写\n\n有时,你可能需要为你的应用的参数和选项指定一个全局默认值。你可以通过在调用 ArgumentParser 构造函数时,将默认值传递给 argument_default 参数来实现这一点(注意:实际上 ArgumentParser 没有 argument_default 这个参数,但这里是为了说明可以全局设置默认值的概念。在实际应用中,你可能需要为每个参数单独设置默认值)。\n这个特性可能并不常用,因为参数和选项通常具有不同的数据类型或意义,很难找到一个满足所有需求的值。\n然而,argument_default(尽管 ArgumentParser 并没有直接提供这个参数,但这里是为了说明概念)的一个常见用例是当你想要避免将参数和选项添加到 Namespace 对象中。在这种情况下,你可以使用 SUPPRESS 常量作为默认值。这个默认值将确保只有命令行中提供的参数和选项才会被存储在 arguments 的 Namespace 中。\n作为一个例子,请继续修改你的自定义 ls 命令,如下面的代码片段所示:\n# ls.py v6\n\nimport argparse\nimport datetime\nfrom pathlib import Path\n\nparser = argparse.ArgumentParser(\n prog="ls",\n description="List the content of a directory",\n epilog="Thanks for using %(prog)s! :)",\n argument_default=argparse.SUPPRESS,\n)\n\n# ...\n\nfor entry in target_dir.iterdir():\n try:\n long = args.long\n except AttributeError:\n long = False\n print(build_output(entry, long=long))\n通过将 SUPPRESS 传递给 ArgumentParser 构造函数,你可以防止未提供的参数被存储在 argparse.Namespace 对象中。这就是为什么在调用 build_output() 之前,你需要检查 -l 或 --long 选项是否实际被传递了。否则,你的代码会因为 args 中不存在 long 属性而引发 AttributeError 错误。\nArgumentParser 的另一个酷炫功能是允许你从外部文件中加载参数值。当你有一个具有冗长或复杂的命令行结构的应用,并希望自动化加载参数值的过程时,这个功能就非常有用。\n在这种情况下,你可以将参数值存储在一个外部文件中,并让你的程序从该文件中加载它们。为了尝试这个功能,请继续创建一个简单的命令行界面(CLI)应用,如下所示:\n# fromfile.py\n\nimport argparse\n\nparser = argparse.ArgumentParser(fromfile_prefix_chars="@")\n\nparser.add_argument("one")\nparser.add_argument("two")\nparser.add_argument("three")\n\nargs = parser.parse_args()\n\nprint(args)\n在这里,你向 ArgumentParser 的 fromfile_prefix_chars 参数传递 @ 符号。然后,你创建了三个必须在命令行中提供的必需参数。\n现在,假设你经常使用此应用程序,并且总是使用相同的一组参数值。为了简化和优化你的工作流程,你可以创建一个文件,其中包含所有必需参数的适当值,每个参数占一行,就像下面的 args.txt 文件一样:\nfirst\nsecond\nthird\n\n有了这个文件,您现在可以调用您的程序并指示它从 args.txt 文件加载值,如以下命令运行所示:\n$ python fromfile.py @args.txt\nNamespace(one=\'first\', two=\'second\', three=\'third\')\n在此命令的输出中,你可以看到 argparse 已经读取了 args.txt 的内容,并顺序地将值分配给了 fromfile.py 程序的每个参数。所有参数及其值都已成功存储在 Namespace 对象中。\n接受缩写选项名称的能力是 argparse 命令行界面(CLI)的另一个酷炫特性。这个特性是默认启用的,当你的程序具有长选项名称时非常有用。例如,考虑以下程序,它会在命令行下打印出你在 --argument-with-a-long-name 选项后指定的值:\n# abbreviate.py\n\nimport argparse\n\nparser = argparse.ArgumentParser()\n\nparser.add_argument("--argument-with-a-long-name")\n\nargs = parser.parse_args()\n\nprint(args.argument_with_a_long_name)\n这个程序会打印出你在 --argument-with-a-long-name 选项后传入的任何参数值。现在,请继续运行以下命令来检查 Python 的 argparse 模块如何处理这些缩写:\n$ python abbreviate.py --argument-with-a-long-name 42\n42\n\n$ python abbreviate.py --argument 42\n42\n\n$ python abbreviate.py --a 42\n42\n这些示例展示了如何缩写 --argument-with-a-long-name 选项的名称,而应用程序仍能正常工作。此功能是默认启用的。如果你希望禁用它并禁止缩写,那么可以在 ArgumentParser 中使用 allow_abbrev 参数:\n# abbreviate.py\n\nimport argparse\n\nparser = argparse.ArgumentParser(allow_abbrev=False)\n\nparser.add_argument("--argument-with-a-long-name")\n\nargs = parser.parse_args()\n\nprint(args.argument_with_a_long_name)\n将 allow_abbrev 设置为 False 会禁用命令行选项中的缩写。从这一点开始,你将需要为程序提供完整的选项名称才能正确工作。否则,你会收到一个错误:\n$ python abbreviate.py --argument-with-a-long-name 42\n42\n\n$ python abbreviate.py --argument 42\nusage: abbreviate.py [-h] [--argument-with-a-long-name ...]\nabbreviate.py: error: unrecognized arguments: --argument 42\n第二个示例中的错误消息告诉你 --argument 选项没有被识别为有效的选项。要使用该选项,你需要提供它的完整名称。\n微调你的命令行参数和选项\n到目前为止,你已经学习了如何定制 ArgumentParser 类的多个功能,以改善你的命令行界面(CLI)的用户体验。现在,你知道了如何调整你的应用程序的使用说明和帮助信息,以及如何微调命令行参数和选项的一些全局方面。\n在本节中,你将学习如何定制你的 CLI 的命令行参数和选项的其他几个功能。在这种情况下,你将使用 .add_argument() 方法及其一些最相关的参数,包括 action、type、nargs、default、help 等。\n设置 Option 背后的 Action\n当你向命令行界面添加一个选项或标志时,通常需要定义如何将选项的值存储在调用 .parse_args() 后得到的 Namespace 对象中。为此,你会使用 .add_argument() 的 action 参数。action 参数的默认值为 "store",意味着提供的选项值将原样存储在 Namespace 中。\naction 参数可以接受几个可能的值。以下是这些可能值的列表及其含义:', 'bodyHTML': '
\n

原文:Build Command-Line Interfaces With Python\'s argparse

\n
\n

命令行应用在普通用户空间中可能并不常见,但它们存在于开发、数据科学、系统管理和许多其他操作中。每个命令行应用都需要一个用户友好的命令行界面 (CLI),以便你可以与应用本身进行交互。在 Python 中,您可以使用标准库中的 argparse 模块创建功能齐全的 CLI。

\n\n

在本文中,你将了解如何:

\n
    \n
  • 命令行界面入门;
  • \n
  • 在 Python 中组织和布局命令行应用项目;
  • \n
  • 使用 Python argparse 创建命令行界面(command-line interfaces);
  • \n
  • 使用 argparse 一些强大的功能深度自定义您的 CLI;
  • \n
\n

若要充分利用本教程,应熟悉 Python 编程,包括面向对象编程、脚本开发和执行以及 Python 包和模块等概念。如果您熟悉与使用命令行或终端相关的一般概念和主题,这也将很有帮助。

\n

了解命令行界面

\n

自从计算机发明以来,人类一直需要并找到与这些机器交互和共享信息的方法。信息交换在人、计算机软件和硬件组件之间流动。其中任意两个元素之间的共享边界通常称为接口(interface)。

\n

在软件开发中,接口是给定软件的特殊部分,它允许计算机系统组件之间的交互。当涉及到人机交互和软件交互时,这个重要的组件被称为用户界面(user interface)。

\n

您会在编程中找到不同类型的用户界面。图形用户界面 (GUI) 可能是当今最常见的。但是,您还可以找到为其用户提供命令行界面 (CLI) 的应用和程序。在本教程中,你将了解 CLI 以及如何在 Python 中创建它们。

\n

命令行界面 (CLI)

\n

命令行界面允许您通过操作系统命令行、终端或控制台与应用程序或程序进行交互。

\n

要了解命令行界面及其工作原理,请考虑此实际示例。假设您有一个名为 sample 包含三个示例文件的目录。如果您使用的是类 Unix 操作系统,例如 Linux 或 macOS,请继续在父目录中打开命令行窗口或终端,然后执行以下命令:

\n
$ ls sample/\nhello.txt     lorem.md      realpython.md
\n

Unix 的 ls 命令列出目标目录中包含的文件和子目录,该目录默认为当前工作目录。上面的命令调用没有显示有关 的内容 sample 的太多信息。它只在屏幕上显示文件名。

\n

假设你想要获取有关目录及其内容的更丰富信息,那么你不需要寻找其他程序,因为 ls 命令有一个功能齐全的命令行界面,并且提供了一组有用的选项,可以用来定制命令的行为。

\n

例如,继续执行带有 -l 选项的 ls 命令:

\n
$ ls -l sample/\ntotal 24\n-rw-r--r--@ 1 user  staff    83 Aug 17 22:15 hello.txt\n-rw-r--r--@ 1 user  staff  2609 Aug 17 22:15 lorem.md\n-rw-r--r--@ 1 user  staff   428 Aug 17 22:15 realpython.md
\n

现在,ls 命令的输出完全不同了。该命令显示了有关 sample 目录中文件的更多信息,包括权限、所有者、组、日期和大小。它还显示了这些文件在你计算机磁盘上使用的总空间。

\n

这种更丰富的输出结果是由于使用了 -l 选项,这是 Unix ls 命令行界面的一部分,它启用了详细的输出格式。

\n

命令、参数、选项、参数和子命令

\n

在本教程中,您将深入了解命令(commands)及其子命令(subcommands),同时还会学习到命令行参数(command-line arguments)、选项(options)和参数(parameters)的相关知识。因此,建议您将这些术语纳入您的技术词汇库中。

\n
    \n
  • 命令(Command):在命令行或终端窗口中运行的程序或例程。通常,您可以通过其背后的程序(underlying program)或例程(routine)的名称来识别一个命令。
  • \n
  • 参数(Argument):命令在执行其预期操作时所需或可选的信息片段。命令通常接受一个或多个参数,您可以在命令行中以空格分隔或逗号分隔的列表形式提供这些参数。
  • \n
  • 选项(Option),也称为 flagswitch:一种可选的参数,用于修改命令的行为。选项通过特定的名称(如前一个示例中的 -l)传递给命令。
  • \n
  • 参数(Parameter):一个选项用于执行其预期操作或动作时所使用的参数。
  • \n
  • 子命令(Subcommand)**:一个预定义的名称,可以传递给应用程序来执行特定的操作。
  • \n
\n

参考上一节中的示例命令结构:

\n
$ ls -l sample/
\n

在这个例子中,您组合了命令行界面(CLI)的以下组件:

\n
    \n
  • ls:命令的名称或应用的名称;
  • \n
  • -l:启用详细输出的选项(option)、开关(switch)或标志(flag);
  • \n
  • sample:为命令执行提供附加信息的参数(argument);
  • \n
\n

现在,让我们来看下面的命令结构,它展示了 Python 包管理器 pip 的命令行界面(CLI):

\n
$ pip install -r requirements.txt
\n

这是一个常见的 pip 命令结构,您可能之前已经见过。它允许您使用 requirements.txt 文件来给指定的 Python 项目安装依赖项。在这个例子中,您使用了以下命令行界面(CLI)组件:

\n
    \n
  • pip:命令的名称;
  • \n
  • installpip 的子命令(subcommand)名称;
  • \n
  • -rinstall 子命令的选项(option);
  • \n
  • requirements.txt:一个参数,特别是 -r 选项的参数。
  • \n
\n

现在您已经了解了命令行界面(CLI)是什么以及其主要部分或组件有哪些。接下来,是时候学习如何在 Python 中创建自己的 CLI 了。

\n

Python 中的 CLI 入门

\n

Python 附带了一些工具,这些工具可帮助您为程序和应用程序编写命令行界面(CLI)。若您需要快速为小型程序构建一个简洁的 CLI,那么可以利用 sys 模块中的 argv 属性。这个属性会自动存储您在命令行中传递给特定程序的参数。

\n

使用 sys.argv 构建最小的 CLI

\n

以使用 argv 创建最小命令行界面(CLI)为例,假设您需要编写一个小程序,该程序类似于 ls 命令,能够列出给定目录下的所有文件。在这种情况下,您可以编写如下代码:

\n
# ls_argv.py\n\nimport sys\nfrom pathlib import Path\n\nif (args_count := len(sys.argv)) > 2:\n    print(f"One argument expected, got {args_count - 1}")\n    raise SystemExit(2)\nelif args_count < 2:\n    print("You must specify the target directory")\n    raise SystemExit(2)\n\ntarget_dir = Path(sys.argv[1])\n\nif not target_dir.is_dir():\n    print("The target directory doesn\'t exist")\n    raise SystemExit(1)\n\nfor entry in target_dir.iterdir():\n    print(entry.name)
\n

该程序通过手动处理命令行提供的参数来实现了一个简单的命令行界面(CLI),这些参数会自动存储在 sys.argv 中。sys.argv 的第一个元素始终是程序名称,第二个元素则是目标目录。由于应用程序不应接受超过一个目标目录,因此 args_count 不得超过 2。

\n

在检查 sys.argv 的内容后,您创建一个pathlib.Path对象来存储目标目录的路径。如果该目录不存在,您将通知用户并退出程序。接下来的for循环将列出目录内容,每行一个条目。

\n

如果从命令行运行该脚本,您将得到以下结果:

\n
$ python ls_argv.py sample/\nhello.txt\nlorem.md\nrealpython.md\n\n$ python ls_argv.py\nYou must specify the target directory\n\n$ python ls_argv.py sample/ other_dir/\nOne argument expected, got 2\n\n$ python ls_argv.py non_existing/\nThe target directory doesn\'t exist
\n

您的程序接受一个目录作为参数,并列出其内容。如果您运行命令时没有提供参数,您将收到一个错误消息。如果您运行命令时指定了超过一个目标目录,您同样会收到一个错误消息。如果尝试运行命令并指定一个不存在的目录,程序将输出另一个错误消息。

\n

虽然您的程序运行正常,但对于更复杂的 CLI 应用程序来说,使用sys.argv属性手动解析命令行参数并不是一个可扩展的解决方案。如果您的应用需要接受更多的参数和选项,那么解析sys.argv将变得复杂且容易出错。您需要一个更好的解决方案,这就是 Python 中的argparse模块所提供的。

\n

使用 argparse 创建 CLI

\n

在 Python 中创建 CLI 应用程序的更便捷方法是使用标准库中的 argparse 模块。该模块首次在 Python 3.2 中随 PEP-389 一同发布,是快速创建 Python CLI 应用程序的利器,无需安装如 Typer 或 Click 这样的第三方库。

\n

argparse 模块是作为较旧的 getoptoptparse 模块的替代品而发布的,因为它们缺乏一些重要的功能。

\n

Python 的 argparse 模块允许您:

\n
    \n
  • 解析命令行参数(arguments)和选项(options);
  • \n
  • 在一个单一选项中接受可变数量的参数(variable number of parameters);
  • \n
  • 在 CLI 中提供子命令(subcommands)。
  • \n
\n

这些特性使 argparse 成为了一个强大的 CLI 框架,您在创建 CLI 应用程序时可以放心地依赖它。要使用 Python 的 argparse,您需要遵循以下四个简单的步骤:

\n
    \n
  1. 导入 argparse
  2. \n
  3. 通过实例化 ArgumentParser 创建参数解析器(argument parser);
  4. \n
  5. 使用 .add_argument() 方法向解析器添加参数(arguments)和选项(options);
  6. \n
  7. 在解析器上调用 .parse_args() 以获取参数 Namespace
  8. \n
\n

例如,您可以使用 argparse 来改进您的 ls_argv.py 脚本。现在,您可以创建一个名为 ls.py 的脚本,并编写以下代码:

\n
# ls.py v1\n\nimport argparse\nfrom pathlib import Path\n\nparser = argparse.ArgumentParser()\n\nparser.add_argument("path")\n\nargs = parser.parse_args()\n\ntarget_dir = Path(args.path)\n\nif not target_dir.exists():\n    print("The target directory doesn\'t exist")\n    raise SystemExit(1)\n\nfor entry in target_dir.iterdir():\n    print(entry.name)
\n

随着 argparse 的引入,您的代码发生了显著的变化。与之前的版本相比,最明显的不同是,用于检查用户提供的参数的条件语句已经消失了。这是因为 argparse 会自动为您检查参数的存在性。

\n

在这个新的实现中,您首先导入 argparse 并创建一个参数解析器。要创建解析器,您可以使用 ArgumentParser 类。接下来,您定义一个名为 path 的参数,用于获取用户的目标目录。

\n

接下来,您需要调用 .parse_args() 方法来解析输入参数,并获取一个包含所有用户参数的 Namespace 对象。请注意,现在 args 变量保存了一个 Namespace 对象,该对象具有从命令行收集的每个参数所对应的属性。

\n

在这个例子中,您只有一个参数,名为 pathNamespace 对象允许您使用点表示法通过 args 来访问 path。其余的代码与第一个实现相同。

\n

现在继续从命令行运行这个新脚本:

\n
$ python ls.py sample/\nlorem.md\nrealpython.md\nhello.txt\n\n$ python ls.py\nusage: ls.py [-h] path\nls.py: error: the following arguments are required: path\n\n$ python ls.py sample/ other_dir/\nusage: ls.py [-h] path\nls.py: error: unrecognized arguments: other_dir/\n\n$ python ls.py non_existing/\nThe target directory doesn\'t exist
\n

第一个命令的输出与您的原始脚本 ls_argv.py 相同。而第二个命令的输出则与 ls_argv.py 中的输出大不相同。程序现在会显示一个使用说明消息,并发出错误提示,告诉您必须提供 path 参数。

\n

在第三个命令中,您传递了两个目标目录,但应用程序并未为此做好准备。因此,它再次显示使用说明消息,并抛出一个错误,告知您潜在的问题。

\n

最后,如果您运行脚本时传递了一个不存在的目录作为参数,那么您会收到一个错误,告知您目标目录不存在,因此程序无法执行其工作。

\n

现在,您可以使用一个新的隐式特性。现在,您的程序接受一个可选的 -h 标志。不妨尝试一下:

\n
$ python ls.py -h\nusage: ls.py [-h] path\n\npositional arguments:\n  path\n\noptions:\n  -h, --help  show this help message and exit
\n

太棒了,现在您的程序会自动响应 -h--help 标志,并为您显示带有使用说明的帮助消息。这真是一个很棒的特性,而且您只需在代码中引入 argparse 就能轻松获得!

\n

经过这个快速介绍如何在 Python 中创建 CLI 应用后,您现在就可以深入研究 argparse 模块及其所有炫酷特性了。

\n

使用 Python 的 argparse 创建 CLI

\n

您可以使用 argparse 模块为您的应用程序和项目编写用户友好的命令行界面。该模块允许您定义应用程序所需的参数和选项。然后,argparse 将负责为您解析 sys.argv 的参数和选项。

\n

argparse 的另一个酷炫特性是它可以自动为您的 CLI 应用程序生成使用说明和帮助消息。该模块还会在参数无效时发出错误提示,并具备更多功能。

\n

在深入研究 argparse 之前,您需要知道该模块的文档可识别两种不同类型的命令行参数:

\n
    \n
  • 位置参数(Positional arguments),您称为参数(arguments);
  • \n
  • 可选参数(Optional arguments),即选项(options)、标志(flags)或开关(switches)。
  • \n
\n

ls.py 的示例中,path 是一个位置参数(positional argument)。这样的参数之所以被称为位置参数,是因为它在命令构造中的相对位置定义了其作用。

\n

与位置参数不同,可选参数(Optional arguments)并不是必需的。它们允许你修改命令的行为。以 Unix 命令 ls 为例,-l 标志就是一个可选参数,它使得命令以详细模式显示输出。

\n

在明确了这些概念之后,你就可以着手使用 Python 和 argparse 库来构建自己的命令行界面(CLI)应用程序了。

\n

创建命令行参数解析器

\n

命令行参数解析器是任何使用 argparse 的命令行界面(CLI)中最为关键的部分。你在命令行上提供的所有参数和选项都会经过这个解析器的处理,它会为你完成繁重的解析工作。

\n

要使用 argparse 创建命令行参数解析器,您需要实例化 ArgumentParser 类:

\n
>>> from argparse import ArgumentParser\n\n>>> parser = ArgumentParser()\n>>> parser\nArgumentParser(\n    prog=\'\',\n    usage=None,\n    description=None,\n    formatter_class=<class \'argparse.HelpFormatter\'>,\n    conflict_handler=\'error\',\n    add_help=True\n)
\n

ArgumentParser 的构造函数接受多种不同的参数,你可以利用这些参数来微调你的 CLI 的多个特性。由于所有这些参数都是可选的,因此你可以通过不传入任何参数直接实例化 ArgumentParser 来创建一个最基本的解析器。

\n

在本教程中,你将会更深入地了解 ArgumentParser 构造函数的参数,特别是在定制你的参数解析器的部分。目前,你可以开始使用 argparse 创建 CLI 的下一步了。这一步就是通过解析器对象来添加参数和选项。

\n

添加参数和选项

\n

要为 argparse 的 CLI 添加参数和选项,你将使用 ArgumentParser 实例的 .add_argument() 方法。请注意,这个方法对参数和选项都是通用的。在 argparse 的术语中,参数被称为位置参数(positional arguments),而选项被称为可选参数(optional arguments)。

\n

.add_argument() 方法的第一个参数决定了参数和选项之间的区别。这个参数被标识为名称(name)或标志(flag)。因此,如果你提供一个 name,那么你将定义一个参数(argument)。相反,如果你使用一个 flag,那么你将添加一个选项(option)。

\n

你已经在使用 argparse 时处理过命令行参数了。现在,考虑以下你自定义的 ls 命令的增强版本,它向 CLI 添加了一个 -l 选项:

\n
# ls.py v2\n\nimport argparse\nimport datetime\nfrom pathlib import Path\n\nparser = argparse.ArgumentParser()\n\nparser.add_argument("path")\n\nparser.add_argument("-l", "--long", action="store_true")\n\nargs = parser.parse_args()\n\ntarget_dir = Path(args.path)\n\nif not target_dir.exists():\n    print("The target directory doesn\'t exist")\n    raise SystemExit(1)\n\ndef build_output(entry, long=False):\n    if long:\n        size = entry.stat().st_size\n        date = datetime.datetime.fromtimestamp(\n            entry.stat().st_mtime).strftime(\n            "%b %d %H:%M:%S"\n        )\n        return f"{size:>6d} {date} {entry.name}"\n    return entry.name\n\nfor entry in target_dir.iterdir():\n    print(build_output(entry, long=args.long))
\n

在这个例子中,第 11 行代码创建了一个带有 -l--long 标志的选项。参数(arguments)和选项(options)在语法上的区别在于,选项名称以短横线 - 开头表示简写标志,以双短横线 -- 开头表示完整标志。

\n

请注意,在这个特定例子中,与 -l--long 选项一同设置了一个 action 参数为 "store_true",这意味着这个选项将存储一个布尔值。如果你在命令行上提供了这个选项,那么它的值将为 True。如果你省略了这个选项,那么它的值将为 False。在 "设置 Option 背后的 Action" 部分内容中,你将了解更多关于 .add_argument() 中的 action 参数的信息。

\n

在第 21 行的 build_output() 函数中,当 longTrue 时,它会返回一个详细的输出,否则返回一个简短的输出。详细的输出将包含目标目录中所有条目的大小、修改日期和名称。它使用了诸如 Path.stat() 这样的工具,以及带有自定义字符串格式的 datetime.datetime 对象。

\n

继续在 sample 上执行您的程序,以检查 -l 选项如何工作:

\n
$ python ls.py -l sample/\n  2609 Oct 28 14:07:04 lorem.md\n   428 Oct 28 14:07:04 realpython.md\n    83 Oct 28 14:07:04 hello.txt
\n

新增的 -l 选项允许你生成并显示关于目标目录内容的更详细输出。

\n

既然你已经知道了如何向 CLI 添加命令行参数和选项,接下来就是深入解析这些参数和选项的时候了。这将是你在接下来部分要探索的内容。

\n

解析命令行参数和选项

\n

解析命令行参数是基于 argparse 的任何 CLI 应用中的另一个重要步骤。一旦你解析了参数,你就可以根据它们的值来执行相应的操作。在你自定义的 ls 命令示例中,参数解析发生在包含 args = parser.parse_args() 语句的行上。

\n

这个语句调用了 .parse_args() 方法,并将其返回值赋给 args 变量。.parse_args() 的返回值是一个 Namespace 对象,其中包含了在命令行上提供的所有参数和选项以及它们对应的值。

\n

考虑以下简单的示例:

\n
>>> from argparse import ArgumentParser\n\n>>> parser = ArgumentParser()\n\n>>> parser.add_argument("site")\n_StoreAction(...)\n\n>>> parser.add_argument("-c", "--connect", action="store_true")\n_StoreTrueAction(...)\n\n>>> args = parser.parse_args(["Real Python", "-c"])\n>>> args\nNamespace(site=\'Real Python\', connect=True)\n\n>>> args.site\n\'Real Python\'\n>>> args.connect\nTrue
\n

通过在命令行参数解析器上调用 .parse_args() 方法得到的 Namespace 对象,你可以使用点表示法(dot notation)访问所有输入参数、选项以及它们对应的值。这样,你就可以检查输入参数和选项的列表,并根据用户在命令行上的选择来执行相应的操作。

\n

你将在应用程序的主代码中使用这个 Namespace 对象。这与你在自定义 ls 命令示例中的 for 循环下所做的类似。

\n

到目前为止,你已经了解了创建基于 argparse 的 CLI 的主要步骤。现在,你可以花些时间学习如何在 Python 中组织和构建 CLI 应用程序的基础知识了。

\n

设置 CLI 应用程序的布局和构建系统

\n

在继续你的 argparse 学习之旅之前,你应该暂停一下,思考如何组织你的代码和规划一个 CLI 项目。首先,你应该考虑以下几点:

\n
    \n
  • 你可以创建模块和包来组织代码。
  • \n
  • 你可以将 Python 应用的核心包命名为应用本身的名字。
  • \n
  • 你会根据每个 Python 模块的具体内容或功能来命名它们。
  • \n
  • 如果你希望某个包可以直接执行,你可以在该 Python 包中添加一个 __main__.py 模块。
  • \n
\n

将这些想法铭记于心,并考虑到模型-视图-控制器(MVC)模式是一种有效组织应用程序结构的方法,你在规划 CLI 项目时可以采用以下目录结构:

\n
hello_cli/\n│\n├── hello_cli/\n│   ├── __init__.py\n│   ├── __main__.py\n│   ├── cli.py\n│   └── model.py\n│\n├── tests/\n│   ├── __init__.py\n│   ├── test_cli.py\n│   └── test_model.py\n│\n├── pyproject.toml\n├── README.md\n└── requirements.txt\n
\n

hello_cli/ 目录是项目的根目录。在那里,您将放置以下文件:

\n
    \n
  • pyproject.toml 是一个 TOML 文件,用于指定项目的构建系统(build system)和其他配置(configurations)。
  • \n
  • README.md 文件提供了项目的描述以及安装和运行应用程序的说明。为你的项目添加一个描述性且详细的 README.md 文件是编程中的最佳实践,特别是如果你打算将项目作为开源解决方案发布的话。
  • \n
  • requirements.txt 是一个常规文件,列出了项目的外部依赖项(external dependencies)。你将使用这个文件,结合 pip-r 选项,来自动安装这些依赖项。
  • \n
\n

接下来是 hello_cli/ 目录,它包含了应用的核心包,该包包含以下模块:

\n
    \n
  • __init__.py 文件使得 hello_cli/ 可以作为一个 Python 包被识别。
  • \n
  • __main__.py 文件提供了应用程序的入口点脚本(entry-point script)或可执行文件,这是启动程序的主要入口。
  • \n
  • cli.py 文件为应用提供了命令行界面。在此文件中的代码将扮演基于 MVC 架构中的视图-控制器角色。
  • \n
  • model.py 文件包含了支持应用主要功能的代码。这部分代码将在你的 MVC 布局中扮演模型角色。
  • \n
\n

你还需要一个 tests/ 包,其中包含针对应用程序组件的单元测试文件。在这个具体的项目布局示例中,你有 test_cli.py 用于检查 CLI 功能的单元测试,以及 test_model.py 用于检查你的模型代码的单元测试。

\n

pyproject.toml 文件允许你定义应用程序的构建系统以及许多其他常规配置。以下是一个如何为你的示例 hello_cli 项目填写此文件的简单示例:

\n
# pyproject.toml\n\n[build-system]\nrequires = ["setuptools>=64.0.0", "wheel"]\nbuild-backend = "setuptools.build_meta"\n\n[project]\nname = "hello_cli"\nversion = "0.0.1"\ndescription = "My awesome Hello CLI application"\nreadme = "README.md"\nauthors = [{ name = "Real Python", email = "info@realpython.com" }]\n\n[project.scripts]\nhello_cli = "hello_cli.__main__:main"
\n

[build-system] 表头将 setuptools 设置为应用程序的构建系统,并指定 Python 需要安装哪些依赖项来构建应用程序。[project] 表头为你的应用提供了通用元数据。这些元数据在你想要将应用发布到 Python 包索引(PyPI)时非常有用。最后, [project.scripts] 表头定义了你的应用程序的入口点。

\n

经过这次对 CLI 项目布局和构建的快速探索,你已经准备好继续学习 argparse 了,特别是如何自定义你的命令行参数解析器。

\n

自定义你的命令行参数解析器

\n

在前面的部分中,你已经学习了如何使用 Python 的 argparse 模块为你的程序或应用实现命令行接口的基础知识。同时,你也了解了如何按照 MVC 模式组织和规划 CLI 应用项目。

\n

在接下来的部分中,你将更深入地探索 argparse 的许多其他强大功能。特别是,你将学习如何在 ArgumentParser 构造函数中使用一些最有用的参数,这将使你能够自定义 CLI 应用的一般行为。

\n

调整程序的 Help 和 Usage 内容

\n

向 CLI 应用程序的用户提供使用说明和帮助是一种最佳实践,可以通过出色的用户体验 (UX) 让用户更加愉快。在本节中,你将了解如何利用 ArgumentParser 的一些参数来微调 CLI 应用程序向用户显示帮助和使用消息的方式。你将学习如何:

\n
    \n
  • 设置程序名称
  • \n
  • 定义程序的描述和结束消息
  • \n
  • 对参数和选项进行分组显示帮助
  • \n
\n

首先,你将开始设置你的程序名称,并指定该名称在帮助或使用说明消息中的显示方式。

\n

设置程序名称

\n

默认情况下,argparse 会使用 sys.argv 中的第一个值来设置程序的名称。这个第一项包含你刚刚执行的 Python 文件的名称。这个文件名在使用说明消息中看起来会有些奇怪。

\n

例如,继续使用 -h 选项运行自定义 ls 命令:

\n
$ python ls.py -h\nusage: ls.py [-h] [-l] path\n\npositional arguments:\n  path\n\noptions:\n  -h, --help  show this help message and exit\n  -l, --long
\n

命令输出中的高亮行显示 argparse 正在使用文件名 ls.py 作为程序的名称。这看起来有些奇怪,因为在使用说明消息中,应用名称很少包含文件扩展名。

\n

幸运的是,你可以使用 prog 参数来指定你的程序名称,就像下面的代码片段所示:

\n
# ls.py v3\n\nimport argparse\nimport datetime\nfrom pathlib import Path\n\nparser = argparse.ArgumentParser(prog="ls")\n\n# ...\n\nfor entry in target_dir.iterdir():\n    print(build_output(entry, long=args.long))
\n

使用 prog 参数,你可以指定将在使用说明消息中使用的程序名称。在这个例子中,你使用了字符串 "ls"。现在,继续运行你的应用:

\n
$ python ls.py -h\nusage: ls [-h] [-l] path\n\npositional arguments:\n  path\n\noptions:\n  -h, --help  show this help message and exit\n  -l, --long
\n

很好!这个输出的第一行中的使用说明消息显示程序名称为 ls,而不是 ls.py

\n

除了设置程序名称外,argparse 还允许你定义应用的描述和结尾信息。在接下来的部分中,你将学习如何进行这两方面的操作。

\n

定义程序的描述和结语消息

\n

你还可以为你的应用定义一个通用的描述和一个结尾或结束语。为此,你将分别使用 descriptionepilog 参数。接下来,请更新 ls.py 文件,在 ArgumentParser 构造函数中添加以下内容:

\n
# ls.py v4\n\nimport argparse\nimport datetime\nfrom pathlib import Path\n\nparser = argparse.ArgumentParser(\n    prog="ls",\n    description="List the content of a directory",\n    epilog="Thanks for using %(prog)s! :)",\n)\n\n# ...\n\nfor entry in target_dir.iterdir():\n    print(build_output(entry, long=args.long))
\n

在这次更新中,description 参数允许你为应用提供一个通用的描述。这个描述将显示在帮助消息的开头。epilog 参数则允许你定义一些文本作为应用的结尾或结束语。请注意,你可以使用旧式的字符串格式化操作符(%)将 prog 参数插入到 epilog 字符串中。

\n

如果再次运行该应用程序,你将得到如下输出:

\n
$ python ls.py -h\nusage: ls [-h] [-l] path\n\nList the content of a directory\n\npositional arguments:\n  path\n\noptions:\n  -h, --help  show this help message and exit\n  -l, --long\n\nThanks for using ls! :)
\n

现在,输出会在使用消息之后显示描述消息,并在帮助文本末尾显示结语消息。

\n

显示参数和选项的分组帮助

\n

帮助分组(Help groups)是 argparse 的另一个有趣特性。它们允许你将相关的命令和参数进行分组,从而帮助你组织应用的帮助消息。要创建这些帮助分组,你将使用 ArgumentParser.add_argument_group() 方法。

\n

作为一个例子,请考虑你自定义的 ls 命令的以下更新版本:

\n
# ls.py v5\n# ...\n\nparser = argparse.ArgumentParser(\n    prog="ls",\n    description="List the content of a directory",\n    epilog="Thanks for using %(prog)s! :)",\n)\n\ngeneral = parser.add_argument_group("general output")\ngeneral.add_argument("path")\n\ndetailed = parser.add_argument_group("detailed output")\ndetailed.add_argument("-l", "--long", action="store_true")\n\nargs = parser.parse_args()\n\n# ...\n\nfor entry in target_dir.iterdir():\n    print(build_output(entry, long=args.long))
\n

在这次更新中,你为显示一般输出的参数和选项创建了一个帮助分组,并为显示详细输出的参数和选项创建了另一个分组。

\n

如果你在命令行中使用 -h 选项运行应用程序,那么你将获得以下输出:

\n
python ls.py -h\nusage: ls [-h] [-l] path\n\nList the content of a directory\n\noptions:\n  -h, --help  show this help message and exit\n\ngeneral output:\n  path\n\ndetailed output:\n  -l, --long\n\nThanks for using ls! :)
\n

现在,你的应用的参数和选项在帮助消息中以描述性的标题进行了方便的分组。这个整洁的特性将帮助你为用户提供更多的上下文,并帮助他们更好地理解应用的工作原理。

\n

为参数和选项提供全局设置

\n

除了自定义使用说明和帮助消息外,ArgumentParser 还允许你对命令行界面(CLI)应用进行其他一些有趣的调整。这些调整包括:

\n
    \n
  • 为参数和选项定义全局默认值
  • \n
  • 从外部文件中加载参数和选项
  • \n
  • 允许或禁止选项缩写
  • \n
\n

有时,你可能需要为你的应用的参数和选项指定一个全局默认值。你可以通过在调用 ArgumentParser 构造函数时,将默认值传递给 argument_default 参数来实现这一点(注意:实际上 ArgumentParser 没有 argument_default 这个参数,但这里是为了说明可以全局设置默认值的概念。在实际应用中,你可能需要为每个参数单独设置默认值)。

\n

这个特性可能并不常用,因为参数和选项通常具有不同的数据类型或意义,很难找到一个满足所有需求的值。

\n

然而,argument_default(尽管 ArgumentParser 并没有直接提供这个参数,但这里是为了说明概念)的一个常见用例是当你想要避免将参数和选项添加到 Namespace 对象中。在这种情况下,你可以使用 SUPPRESS 常量作为默认值。这个默认值将确保只有命令行中提供的参数和选项才会被存储在 argumentsNamespace 中。

\n

作为一个例子,请继续修改你的自定义 ls 命令,如下面的代码片段所示:

\n
# ls.py v6\n\nimport argparse\nimport datetime\nfrom pathlib import Path\n\nparser = argparse.ArgumentParser(\n    prog="ls",\n    description="List the content of a directory",\n    epilog="Thanks for using %(prog)s! :)",\n    argument_default=argparse.SUPPRESS,\n)\n\n# ...\n\nfor entry in target_dir.iterdir():\n    try:\n        long = args.long\n    except AttributeError:\n        long = False\n    print(build_output(entry, long=long))
\n

通过将 SUPPRESS 传递给 ArgumentParser 构造函数,你可以防止未提供的参数被存储在 argparse.Namespace 对象中。这就是为什么在调用 build_output() 之前,你需要检查 -l--long 选项是否实际被传递了。否则,你的代码会因为 args 中不存在 long 属性而引发 AttributeError 错误。

\n

ArgumentParser 的另一个酷炫功能是允许你从外部文件中加载参数值。当你有一个具有冗长或复杂的命令行结构的应用,并希望自动化加载参数值的过程时,这个功能就非常有用。

\n

在这种情况下,你可以将参数值存储在一个外部文件中,并让你的程序从该文件中加载它们。为了尝试这个功能,请继续创建一个简单的命令行界面(CLI)应用,如下所示:

\n
# fromfile.py\n\nimport argparse\n\nparser = argparse.ArgumentParser(fromfile_prefix_chars="@")\n\nparser.add_argument("one")\nparser.add_argument("two")\nparser.add_argument("three")\n\nargs = parser.parse_args()\n\nprint(args)
\n

在这里,你向 ArgumentParserfromfile_prefix_chars 参数传递 @ 符号。然后,你创建了三个必须在命令行中提供的必需参数。

\n

现在,假设你经常使用此应用程序,并且总是使用相同的一组参数值。为了简化和优化你的工作流程,你可以创建一个文件,其中包含所有必需参数的适当值,每个参数占一行,就像下面的 args.txt 文件一样:

\n
first\nsecond\nthird\n
\n

有了这个文件,您现在可以调用您的程序并指示它从 args.txt 文件加载值,如以下命令运行所示:

\n
$ python fromfile.py @args.txt\nNamespace(one=\'first\', two=\'second\', three=\'third\')
\n

在此命令的输出中,你可以看到 argparse 已经读取了 args.txt 的内容,并顺序地将值分配给了 fromfile.py 程序的每个参数。所有参数及其值都已成功存储在 Namespace 对象中。

\n

接受缩写选项名称的能力是 argparse 命令行界面(CLI)的另一个酷炫特性。这个特性是默认启用的,当你的程序具有长选项名称时非常有用。例如,考虑以下程序,它会在命令行下打印出你在 --argument-with-a-long-name 选项后指定的值:

\n
# abbreviate.py\n\nimport argparse\n\nparser = argparse.ArgumentParser()\n\nparser.add_argument("--argument-with-a-long-name")\n\nargs = parser.parse_args()\n\nprint(args.argument_with_a_long_name)
\n

这个程序会打印出你在 --argument-with-a-long-name 选项后传入的任何参数值。现在,请继续运行以下命令来检查 Python 的 argparse 模块如何处理这些缩写:

\n
$ python abbreviate.py --argument-with-a-long-name 42\n42\n\n$ python abbreviate.py --argument 42\n42\n\n$ python abbreviate.py --a 42\n42
\n

这些示例展示了如何缩写 --argument-with-a-long-name 选项的名称,而应用程序仍能正常工作。此功能是默认启用的。如果你希望禁用它并禁止缩写,那么可以在 ArgumentParser 中使用 allow_abbrev 参数:

\n
# abbreviate.py\n\nimport argparse\n\nparser = argparse.ArgumentParser(allow_abbrev=False)\n\nparser.add_argument("--argument-with-a-long-name")\n\nargs = parser.parse_args()\n\nprint(args.argument_with_a_long_name)
\n

allow_abbrev 设置为 False 会禁用命令行选项中的缩写。从这一点开始,你将需要为程序提供完整的选项名称才能正确工作。否则,你会收到一个错误:

\n
$ python abbreviate.py --argument-with-a-long-name 42\n42\n\n$ python abbreviate.py --argument 42\nusage: abbreviate.py [-h] [--argument-with-a-long-name ...]\nabbreviate.py: error: unrecognized arguments: --argument 42
\n

第二个示例中的错误消息告诉你 --argument 选项没有被识别为有效的选项。要使用该选项,你需要提供它的完整名称。

\n

微调你的命令行参数和选项

\n

到目前为止,你已经学习了如何定制 ArgumentParser 类的多个功能,以改善你的命令行界面(CLI)的用户体验。现在,你知道了如何调整你的应用程序的使用说明和帮助信息,以及如何微调命令行参数和选项的一些全局方面。

\n

在本节中,你将学习如何定制你的 CLI 的命令行参数和选项的其他几个功能。在这种情况下,你将使用 .add_argument() 方法及其一些最相关的参数,包括 actiontypenargsdefaulthelp 等。

\n

设置 Option 背后的 Action

\n

当你向命令行界面添加一个选项或标志时,通常需要定义如何将选项的值存储在调用 .parse_args() 后得到的 Namespace 对象中。为此,你会使用 .add_argument()action 参数。action 参数的默认值为 "store",意味着提供的选项值将原样存储在 Namespace 中。

\n

action 参数可以接受几个可能的值。以下是这些可能值的列表及其含义:

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.2-编程'}, 'labels': {'nodes': [{'name': '1.2.3-Python'}]}, 'comments': {'nodes': []}}, {'title': 'Chrome/Edge 地址栏正常显示完整的 URL', 'number': 74, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/74', 'createdAt': '2024-05-29T01:22:53Z', 'lastEditedAt': '2024-06-03T05:23:53Z', 'updatedAt': '2024-06-03T05:23:53Z', 'body': '对于在 Chrome/Edge 使用 IP 或者其他 URL 访问网页,地址栏想复制 IP/URL 非要给我自动加上 `http://`(或者 `https://`) 前缀。\r\n\r\n\r\n\r\n## Chrome\r\n\r\nGoogle Chrome 对于这个问题的解决方法很简单:在 URL 地址栏点击 "鼠标右键" -> 选择 "总是显示完整网址"。\r\n\r\n![chrome-show-url](https://kg.weiyan.cc/2024/06/chrome-show-url.png)\r\n\r\n## Edge\r\n\r\n1. 右键点击 Microsoft Edge 的桌面快捷方式,选择属性。\r\n ![edge-1](https://kg.weiyan.cc/2024/05/edge-1.png)\r\n\r\n2. 在启动目标结尾追加空格以及下面这段代码并保存。\r\n ```\r\n --disable-features=msHideSteadyStateUrlPath\r\n ```\r\n ![edge-disable-features](https://kg.weiyan.cc/2024/05/edge-disable-features.png)\r\n\r\n3. 重启浏览器后地址栏就可以显示完整 URL 了。', 'bodyText': '对于在 Chrome/Edge 使用 IP 或者其他 URL 访问网页,地址栏想复制 IP/URL 非要给我自动加上 http://(或者 https://) 前缀。\n\nChrome\nGoogle Chrome 对于这个问题的解决方法很简单:在 URL 地址栏点击 "鼠标右键" -> 选择 "总是显示完整网址"。\n\nEdge\n\n\n右键点击 Microsoft Edge 的桌面快捷方式,选择属性。\n\n\n\n在启动目标结尾追加空格以及下面这段代码并保存。\n--disable-features=msHideSteadyStateUrlPath\n\n\n\n\n重启浏览器后地址栏就可以显示完整 URL 了。', 'bodyHTML': '

对于在 Chrome/Edge 使用 IP 或者其他 URL 访问网页,地址栏想复制 IP/URL 非要给我自动加上 http://(或者 https://) 前缀。

\n\n

Chrome

\n

Google Chrome 对于这个问题的解决方法很简单:在 URL 地址栏点击 "鼠标右键" -> 选择 "总是显示完整网址"。

\n

chrome-show-url

\n

Edge

\n
    \n
  1. \n

    右键点击 Microsoft Edge 的桌面快捷方式,选择属性。
    \nedge-1

    \n
  2. \n
  3. \n

    在启动目标结尾追加空格以及下面这段代码并保存。

    \n
    --disable-features=msHideSteadyStateUrlPath\n
    \n

    edge-disable-features

    \n
  4. \n
  5. \n

    重启浏览器后地址栏就可以显示完整 URL 了。

    \n
  6. \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '适合我的 RSS 阅读器', 'number': 73, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/73', 'createdAt': '2024-05-21T05:51:39Z', 'lastEditedAt': '2024-05-21T06:16:08Z', 'updatedAt': '2024-05-21T06:18:31Z', 'body': '好多年前,写过一篇文章《[使用RSS打造你的科研资讯头条](https://zhuanlan.zhihu.com/p/42088810)》,但是由于没有趁手的 RSS 阅读器以至于让 RSS 信息聚合的这个念头荒废了好多年。直到最近用上了 [QiReader](https://github.com/oxyry/qireader) - 优雅的在线 RSS 阅读器,我的 RSS 信息聚合好像又找到了延续下去的动力。 \r\n\r\n\r\n\r\n不得不说,它很好的满足了我 Web 端+移动端同步的使用需求,而且国内国外通用。\r\n\r\n![qireader-twitter](https://kg.weiyan.cc/2024/05/qireader-twitter.png)\r\n\r\n在价格层面,一年 Pro 会员 ¥38,二年 ¥68,五年 ¥128,也不算贵 —— 于是,果断入手了。\r\n\r\n![qireader-plans](https://kg.weiyan.cc/2024/05/qireader-plans.webp)', 'bodyText': '好多年前,写过一篇文章《使用RSS打造你的科研资讯头条》,但是由于没有趁手的 RSS 阅读器以至于让 RSS 信息聚合的这个念头荒废了好多年。直到最近用上了 QiReader - 优雅的在线 RSS 阅读器,我的 RSS 信息聚合好像又找到了延续下去的动力。\n\n不得不说,它很好的满足了我 Web 端+移动端同步的使用需求,而且国内国外通用。\n\n在价格层面,一年 Pro 会员 ¥38,二年 ¥68,五年 ¥128,也不算贵 —— 于是,果断入手了。', 'bodyHTML': '

好多年前,写过一篇文章《使用RSS打造你的科研资讯头条》,但是由于没有趁手的 RSS 阅读器以至于让 RSS 信息聚合的这个念头荒废了好多年。直到最近用上了 QiReader - 优雅的在线 RSS 阅读器,我的 RSS 信息聚合好像又找到了延续下去的动力。

\n\n

不得不说,它很好的满足了我 Web 端+移动端同步的使用需求,而且国内国外通用。

\n

qireader-twitter

\n

在价格层面,一年 Pro 会员 ¥38,二年 ¥68,五年 ¥128,也不算贵 —— 于是,果断入手了。

\n

qireader-plans

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'Twitter', 'number': 72, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/72', 'createdAt': '2024-05-16T01:58:18Z', 'lastEditedAt': '2024-05-28T03:22:30Z', 'updatedAt': '2024-05-28T03:22:30Z', 'body': '相比微博,Twitter 更有意思一些,除了可以获取到很多技术大咖的日常和动态,还能发现不少有意思的人和事。加上推特世界性的,开放性的一些特点,所以可以看到的自然是什么都有也比国内精彩。\r\n\r\n\r\n\r\n能够翻出来的都是有点认知的人,虽然不一定全对,但也有一定道理。\r\n\r\n微博用的比较少,感觉更加偏向娱乐和一些时事热点。', 'bodyText': '相比微博,Twitter 更有意思一些,除了可以获取到很多技术大咖的日常和动态,还能发现不少有意思的人和事。加上推特世界性的,开放性的一些特点,所以可以看到的自然是什么都有也比国内精彩。\n\n能够翻出来的都是有点认知的人,虽然不一定全对,但也有一定道理。\n微博用的比较少,感觉更加偏向娱乐和一些时事热点。', 'bodyHTML': '

相比微博,Twitter 更有意思一些,除了可以获取到很多技术大咖的日常和动态,还能发现不少有意思的人和事。加上推特世界性的,开放性的一些特点,所以可以看到的自然是什么都有也比国内精彩。

\n\n

能够翻出来的都是有点认知的人,虽然不一定全对,但也有一定道理。

\n

微博用的比较少,感觉更加偏向娱乐和一些时事热点。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'mamba 的两个分支 miniforge 和 mambaforge', 'number': 71, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/71', 'createdAt': '2024-04-28T02:44:00Z', 'lastEditedAt': '2024-06-26T03:00:57Z', 'updatedAt': '2024-06-26T03:00:57Z', 'body': "在安装 mamba 的时候在 [release](https://github.com/conda-forge/miniforge/releases) 页面和[官方的安装页面](https://mamba.readthedocs.io/en/latest/installation/mamba-installation.html) 总是看到关于 miniforge 和 mambaforge 的选择问题,傻傻搞不明白。\r\n\r\n\r\n\r\n## Miniforge 和 Mambaforge\r\n\r\n参考:\r\n\r\n> **What's the difference between Mambaforge and Miniforge?** \r\n> After the release of Miniforge 23.3.1 in August 2023, Miniforge and Mambaforge are essentially identical. The only difference is the name of the installer and subsequently the default installation path.\r\n> \r\n> 2023 年 8 月发布 Miniforge 23.3.1 后,Miniforge 和 Mambaforge 基本相同。唯一的区别是安装程序的名称以及随后的默认安装路径(一个默认是 miniforge3,一个默认是 mambaforge3)。\r\n> \r\n> Before that release, Miniforge only shipped conda, while Mambaforge added mamba on top. Since Miniconda started shipping conda-libmamba-solver in July 2023, Miniforge followed suit and started shipping it too in August. At that point, since conda-libmamba-solver depends on libmambapy, the only difference between Miniforge and Mambaforge was the presence of the mamba Python package. To minimize surprises, we decided to add mamba to Miniforge too. \r\n> \r\n> 在之前的版本中,Miniforge 仅提供 conda,而 Mambaforge 在此基础上增加了 mamba。自 2023 年 7 月 Miniconda 开始提供 conda-libmamba-solver 以来,Miniforge 也紧随其后,于 8 月开始提供此功能。那时,由于 conda-libmamba-solver 依赖于libmambapy,Miniforge 和 Mambaforge 之间的唯一区别就是是否包含 mamba Pytho n包。为了尽量减少意外情况,我们决定也在 Miniforge 中添加 mamba。\r\n> \r\n> **Should I choose one or another going forward at the risk of one of them gettting deprecated?** \r\n> Given its wide usage, there are no plans to deprecate Mambaforge. If at some point we decide to deprecate Mambaforge, it will be appropriately announced and communicated with sufficient time in advance.\r\n> \r\n> 鉴于 Mambaforge 的广泛使用,目前没有计划将其弃用。如果未来我们决定弃用 Mambaforge,我们会提前充分公告并通知相关用户。\r\n> \r\n> That said, if you had to start using one today, we recommend to stick to Miniforge.\r\n> \r\n> 不过,如果你今天需要开始使用其中一个,我们建议你坚持使用 Miniforge。\r\n\r\n## Miniforge 和 Miniconda\r\n\r\n参考:[What’s the difference between Anaconda, conda, Miniconda, mamba, Mambaforge, micromamba?](https://bioconda.github.io/faqs.html#what-s-the-difference-between-anaconda-conda-miniconda-mamba-mambaforge-micromamba) - bioconda#Faqs\r\n\r\nMiniforge 是社区 (conda-forge) 驱动的简约 conda 安装程序。Miniforge 与 Miniconda 类似,但预配置了 `conda-forge` 通道,并且所有包都来自 conda-forge 而不是 `defaults` 通道。现在它还包含了 mamba 和 libmamba。\r\n\r\nMiniconda 是公司 (Anaconda) 驱动的简约 conda 安装程序。随后的软件包安装来自 anaconda 频道(默认或其他)。\r\n\r\n## 一句话\r\n\r\n总的一句话来说,Mambaforge 类似于 Miniforge,但将 mamba 安装到基础环境中。虽然没有严格弃用,但从 **2023 年 9 月**起不鼓励使用它(请参阅 miniforge 自述 [README](https://github.com/conda-forge/miniforge) 文件)。\r\n\r\n\r\n", 'bodyText': "在安装 mamba 的时候在 release 页面和官方的安装页面 总是看到关于 miniforge 和 mambaforge 的选择问题,傻傻搞不明白。\n\nMiniforge 和 Mambaforge\n参考:https://github.com/conda-forge/miniforge?tab=readme-ov-file#faq\n\nWhat's the difference between Mambaforge and Miniforge?\nAfter the release of Miniforge 23.3.1 in August 2023, Miniforge and Mambaforge are essentially identical. The only difference is the name of the installer and subsequently the default installation path.\n2023 年 8 月发布 Miniforge 23.3.1 后,Miniforge 和 Mambaforge 基本相同。唯一的区别是安装程序的名称以及随后的默认安装路径(一个默认是 miniforge3,一个默认是 mambaforge3)。\nBefore that release, Miniforge only shipped conda, while Mambaforge added mamba on top. Since Miniconda started shipping conda-libmamba-solver in July 2023, Miniforge followed suit and started shipping it too in August. At that point, since conda-libmamba-solver depends on libmambapy, the only difference between Miniforge and Mambaforge was the presence of the mamba Python package. To minimize surprises, we decided to add mamba to Miniforge too.\n在之前的版本中,Miniforge 仅提供 conda,而 Mambaforge 在此基础上增加了 mamba。自 2023 年 7 月 Miniconda 开始提供 conda-libmamba-solver 以来,Miniforge 也紧随其后,于 8 月开始提供此功能。那时,由于 conda-libmamba-solver 依赖于libmambapy,Miniforge 和 Mambaforge 之间的唯一区别就是是否包含 mamba Pytho n包。为了尽量减少意外情况,我们决定也在 Miniforge 中添加 mamba。\nShould I choose one or another going forward at the risk of one of them gettting deprecated?\nGiven its wide usage, there are no plans to deprecate Mambaforge. If at some point we decide to deprecate Mambaforge, it will be appropriately announced and communicated with sufficient time in advance.\n鉴于 Mambaforge 的广泛使用,目前没有计划将其弃用。如果未来我们决定弃用 Mambaforge,我们会提前充分公告并通知相关用户。\nThat said, if you had to start using one today, we recommend to stick to Miniforge.\n不过,如果你今天需要开始使用其中一个,我们建议你坚持使用 Miniforge。\n\nMiniforge 和 Miniconda\n参考:What’s the difference between Anaconda, conda, Miniconda, mamba, Mambaforge, micromamba? - bioconda#Faqs\nMiniforge 是社区 (conda-forge) 驱动的简约 conda 安装程序。Miniforge 与 Miniconda 类似,但预配置了 conda-forge 通道,并且所有包都来自 conda-forge 而不是 defaults 通道。现在它还包含了 mamba 和 libmamba。\nMiniconda 是公司 (Anaconda) 驱动的简约 conda 安装程序。随后的软件包安装来自 anaconda 频道(默认或其他)。\n一句话\n总的一句话来说,Mambaforge 类似于 Miniforge,但将 mamba 安装到基础环境中。虽然没有严格弃用,但从 2023 年 9 月起不鼓励使用它(请参阅 miniforge 自述 README 文件)。", 'bodyHTML': '

在安装 mamba 的时候在 release 页面和官方的安装页面 总是看到关于 miniforge 和 mambaforge 的选择问题,傻傻搞不明白。

\n\n

Miniforge 和 Mambaforge

\n

参考:https://github.com/conda-forge/miniforge?tab=readme-ov-file#faq

\n
\n

What\'s the difference between Mambaforge and Miniforge?
\nAfter the release of Miniforge 23.3.1 in August 2023, Miniforge and Mambaforge are essentially identical. The only difference is the name of the installer and subsequently the default installation path.

\n

2023 年 8 月发布 Miniforge 23.3.1 后,Miniforge 和 Mambaforge 基本相同。唯一的区别是安装程序的名称以及随后的默认安装路径(一个默认是 miniforge3,一个默认是 mambaforge3)。

\n

Before that release, Miniforge only shipped conda, while Mambaforge added mamba on top. Since Miniconda started shipping conda-libmamba-solver in July 2023, Miniforge followed suit and started shipping it too in August. At that point, since conda-libmamba-solver depends on libmambapy, the only difference between Miniforge and Mambaforge was the presence of the mamba Python package. To minimize surprises, we decided to add mamba to Miniforge too.

\n

在之前的版本中,Miniforge 仅提供 conda,而 Mambaforge 在此基础上增加了 mamba。自 2023 年 7 月 Miniconda 开始提供 conda-libmamba-solver 以来,Miniforge 也紧随其后,于 8 月开始提供此功能。那时,由于 conda-libmamba-solver 依赖于libmambapy,Miniforge 和 Mambaforge 之间的唯一区别就是是否包含 mamba Pytho n包。为了尽量减少意外情况,我们决定也在 Miniforge 中添加 mamba。

\n

Should I choose one or another going forward at the risk of one of them gettting deprecated?
\nGiven its wide usage, there are no plans to deprecate Mambaforge. If at some point we decide to deprecate Mambaforge, it will be appropriately announced and communicated with sufficient time in advance.

\n

鉴于 Mambaforge 的广泛使用,目前没有计划将其弃用。如果未来我们决定弃用 Mambaforge,我们会提前充分公告并通知相关用户。

\n

That said, if you had to start using one today, we recommend to stick to Miniforge.

\n

不过,如果你今天需要开始使用其中一个,我们建议你坚持使用 Miniforge。

\n
\n

Miniforge 和 Miniconda

\n

参考:What’s the difference between Anaconda, conda, Miniconda, mamba, Mambaforge, micromamba? - bioconda#Faqs

\n

Miniforge 是社区 (conda-forge) 驱动的简约 conda 安装程序。Miniforge 与 Miniconda 类似,但预配置了 conda-forge 通道,并且所有包都来自 conda-forge 而不是 defaults 通道。现在它还包含了 mamba 和 libmamba。

\n

Miniconda 是公司 (Anaconda) 驱动的简约 conda 安装程序。随后的软件包安装来自 anaconda 频道(默认或其他)。

\n

一句话

\n

总的一句话来说,Mambaforge 类似于 Miniforge,但将 mamba 安装到基础环境中。虽然没有严格弃用,但从 2023 年 9 月起不鼓励使用它(请参阅 miniforge 自述 README 文件)。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '1.3.22-虚拟环境'}]}, 'comments': {'nodes': []}}, {'title': '寻找 GitHub 的替代品', 'number': 70, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/70', 'createdAt': '2024-04-24T02:15:48Z', 'lastEditedAt': '2024-09-05T02:18:00Z', 'updatedAt': '2024-09-05T02:18:00Z', 'body': '与其说是在寻找 GitHub 的替代品,倒不如说在寻找 GitHub 的备用站点 —— 以防万一 GitHub 哪天登不上去了,也不至于把托管在上面的东西都丢了,尤其对于我这种几乎把所有可公开文档都记录在 [GitHub Discussions](https://github.com/shenweiyan/Knowledge-Garden/discussions) 上的人,毕竟把所有的鸡蛋放在一个篮子里终究是很危险的。\r\n\r\n\r\n\r\n## 代码\r\n\r\n如果纯粹是代码托管,这样的备用平台多的是。\r\n\r\n除去国内的那几家,国外优秀的托管平台更多一些。如 [Framagit](https://framagit.org/) 和 [Codeberg](https://codeberg.org/)。[Framagit](https://framagit.org/) 是一个基于 GitLab 的法国托管平台,而 [Codeberg](https://codeberg.org/) 则是一个站点(总部)在德国,由非盈利组织采用自由软件(Gitea)搭建的代码托管平台,两相比较,个人感觉 [Codeberg](https://codeberg.org/) 比 [Framagit](https://framagit.org/) 体验更友好,最起码文档和各种导航操作更加清晰明了。\r\n\r\n最最重要的一点是,这两个托管平台目前国内都可以直接连接。\r\n\r\n## Issues 和 Discussions\r\n\r\n如果说 Issues 和 Discussions 的备用站点,这个就不好说了。国内的 [GitCode](https://gitcode.com/) 和 [AtomGit](https://atomgit.com/) 虽然都有类似的功能,但是**都不能搜索内容**,虽然他们说全文搜索已经[在路上了](https://atomgit.com/atomgit_operate/feedback/issues/496),但是背后的 CSDN 运营和 UI 风格真是让人有点担忧重蹈 CSDN 的尿性体验。\r\n\r\n尤其是最近(2024年6月)这一段时间 GitCode 被曝[批量搬运 Github 项目](https://www.ithome.com/0/778/049.htm)的事件,让本来对 CSDN 厌恶至极的我瞬间好感全无,开始对 GitCode 也时刻保持警戒心态。\r\n\r\n## Pages\r\n\r\nGitee Pages 在五一[悄悄关停了](https://gitee.com/oschina/git-osc/issues/I9L5FJ) 也终于让人对国内代码托管平台开启 Pages 服务不再抱有期待。虽然最近发现 [AtomGit](https://atomgit.com/) 也提供了 [AtomGit Pages](https://atomgit.com/apps/pages),而且也的确能正常的用起来了,但谁能确保未来会不会也跟 Gitee Pages 一个下场!\r\n\r\n![atomgit-pages-for-atomgit](https://kg.weiyan.cc/2024/07/atomgit-pages-for-atomgit.jpg)\r\n\r\n## 想法\r\n\r\n由于国内监管的一些问题,国内的开源社区大多都让人一言难尽,曾经的极狐也因为收费的问题把个人用户的最后一根稻草给压垮了,总的来说,国内目前为止就还没有一家能跟得上 GitHub/GitLab 的开源平台,不管从开源本身还是功能体验,现在没有,未来也不一定能有。\r\n\r\n用了一段时间 AtomGit,页面 UI 真是无法忍受,一堆的 BUG 毫无修复([issues#442](https://atomgit.com/atomgit_operate/feedback/issues/442)、[issues#668](https://atomgit.com/atomgit_operate/feedback/issues/668)),用户体验全无。还是先在 GitCode,继续苟着吧!', 'bodyText': '与其说是在寻找 GitHub 的替代品,倒不如说在寻找 GitHub 的备用站点 —— 以防万一 GitHub 哪天登不上去了,也不至于把托管在上面的东西都丢了,尤其对于我这种几乎把所有可公开文档都记录在 GitHub Discussions 上的人,毕竟把所有的鸡蛋放在一个篮子里终究是很危险的。\n\n代码\n如果纯粹是代码托管,这样的备用平台多的是。\n除去国内的那几家,国外优秀的托管平台更多一些。如 Framagit 和 Codeberg。Framagit 是一个基于 GitLab 的法国托管平台,而 Codeberg 则是一个站点(总部)在德国,由非盈利组织采用自由软件(Gitea)搭建的代码托管平台,两相比较,个人感觉 Codeberg 比 Framagit 体验更友好,最起码文档和各种导航操作更加清晰明了。\n最最重要的一点是,这两个托管平台目前国内都可以直接连接。\nIssues 和 Discussions\n如果说 Issues 和 Discussions 的备用站点,这个就不好说了。国内的 GitCode 和 AtomGit 虽然都有类似的功能,但是都不能搜索内容,虽然他们说全文搜索已经在路上了,但是背后的 CSDN 运营和 UI 风格真是让人有点担忧重蹈 CSDN 的尿性体验。\n尤其是最近(2024年6月)这一段时间 GitCode 被曝批量搬运 Github 项目的事件,让本来对 CSDN 厌恶至极的我瞬间好感全无,开始对 GitCode 也时刻保持警戒心态。\nPages\nGitee Pages 在五一悄悄关停了 也终于让人对国内代码托管平台开启 Pages 服务不再抱有期待。虽然最近发现 AtomGit 也提供了 AtomGit Pages,而且也的确能正常的用起来了,但谁能确保未来会不会也跟 Gitee Pages 一个下场!\n\n想法\n由于国内监管的一些问题,国内的开源社区大多都让人一言难尽,曾经的极狐也因为收费的问题把个人用户的最后一根稻草给压垮了,总的来说,国内目前为止就还没有一家能跟得上 GitHub/GitLab 的开源平台,不管从开源本身还是功能体验,现在没有,未来也不一定能有。\n用了一段时间 AtomGit,页面 UI 真是无法忍受,一堆的 BUG 毫无修复(issues#442、issues#668),用户体验全无。还是先在 GitCode,继续苟着吧!', 'bodyHTML': '

与其说是在寻找 GitHub 的替代品,倒不如说在寻找 GitHub 的备用站点 —— 以防万一 GitHub 哪天登不上去了,也不至于把托管在上面的东西都丢了,尤其对于我这种几乎把所有可公开文档都记录在 GitHub Discussions 上的人,毕竟把所有的鸡蛋放在一个篮子里终究是很危险的。

\n\n

代码

\n

如果纯粹是代码托管,这样的备用平台多的是。

\n

除去国内的那几家,国外优秀的托管平台更多一些。如 FramagitCodebergFramagit 是一个基于 GitLab 的法国托管平台,而 Codeberg 则是一个站点(总部)在德国,由非盈利组织采用自由软件(Gitea)搭建的代码托管平台,两相比较,个人感觉 CodebergFramagit 体验更友好,最起码文档和各种导航操作更加清晰明了。

\n

最最重要的一点是,这两个托管平台目前国内都可以直接连接。

\n

Issues 和 Discussions

\n

如果说 Issues 和 Discussions 的备用站点,这个就不好说了。国内的 GitCodeAtomGit 虽然都有类似的功能,但是都不能搜索内容,虽然他们说全文搜索已经在路上了,但是背后的 CSDN 运营和 UI 风格真是让人有点担忧重蹈 CSDN 的尿性体验。

\n

尤其是最近(2024年6月)这一段时间 GitCode 被曝批量搬运 Github 项目的事件,让本来对 CSDN 厌恶至极的我瞬间好感全无,开始对 GitCode 也时刻保持警戒心态。

\n

Pages

\n

Gitee Pages 在五一悄悄关停了 也终于让人对国内代码托管平台开启 Pages 服务不再抱有期待。虽然最近发现 AtomGit 也提供了 AtomGit Pages,而且也的确能正常的用起来了,但谁能确保未来会不会也跟 Gitee Pages 一个下场!

\n

atomgit-pages-for-atomgit

\n

想法

\n

由于国内监管的一些问题,国内的开源社区大多都让人一言难尽,曾经的极狐也因为收费的问题把个人用户的最后一根稻草给压垮了,总的来说,国内目前为止就还没有一家能跟得上 GitHub/GitLab 的开源平台,不管从开源本身还是功能体验,现在没有,未来也不一定能有。

\n

用了一段时间 AtomGit,页面 UI 真是无法忍受,一堆的 BUG 毫无修复(issues#442issues#668),用户体验全无。还是先在 GitCode,继续苟着吧!

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': [{'name': '公众号'}]}, 'comments': {'nodes': []}}, {'title': '我的独立站点 Knowledge-Garden', 'number': 69, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/69', 'createdAt': '2024-04-22T07:37:31Z', 'lastEditedAt': '2024-04-22T07:38:53Z', 'updatedAt': '2024-04-22T07:38:53Z', 'body': '使用 GitHub Discussions 写作文章大半年以来,越来越得心应手,最近起用了新的一个仓库,用于 [Knowledge-Garden](https://github.com/shenweiyan/Knowledge-Garden/discussions) 静态资源的保存和使用。\r\n\r\n\r\n\r\n## 文章\r\n\r\n所有的文章都是以 markdown 的格式进行保存,实际上就一堆 text 文本,占用不了多少的空间。\r\n\r\n## 静态资源\r\n\r\n文章的静态资源,主要是图片,才是一个最耗流量和存储空间的东西。\r\n\r\n前一段时间经历了[腾讯云 cos 对象存储被盗刷](https://github.com/shenweiyan/Knowledge-Garden/discussions/63) 的事件后,对于对象存储的使用也就越来越谨慎,今天终于狠下决心来把 [Knowledge-Garden](https://github.com/shenweiyan/Knowledge-Garden/discussions) 这个仓库的所有包括图片在内的静态资源开始保存到另外一个 GitHub 仓库 [PicKG](https://github.com/shenweiyan/PicKG),同时借助 Cloudflare Pages 来为图片提供访问链接。\r\n\r\n也尝试了一下 Cloudflare 的 [R2](https://www.cloudflare.com/zh-cn/developer-platform/r2/) 这个号称零出口费用的对象存储,免费额度很有吸引力,但目前 Cloudflare R2 还没能找到一个比较顺手的图片管理工具,例如阿里云的 [oss-browser](https://github.com/aliyun/oss-browser)、腾讯云的 [cos-browser](https://cosbrowser.cloud.tencent.com/)。虽然尝试了一些折中的方案,如 [Picx4R2](https://github.com/shenweiyan/Picx4R2),但还是不太满意。\r\n\r\n所以目前的解决方法就是 GitHub + [PicX](https://github.com/shenweiyan/Knowledge-Garden/discussions/68) + Cloudflare Pages 进行组合,GitHub 单个仓库 5G 的存储空间应该应该也足够使用了,如果实在不够了再来考虑其他方案。', 'bodyText': '使用 GitHub Discussions 写作文章大半年以来,越来越得心应手,最近起用了新的一个仓库,用于 Knowledge-Garden 静态资源的保存和使用。\n\n文章\n所有的文章都是以 markdown 的格式进行保存,实际上就一堆 text 文本,占用不了多少的空间。\n静态资源\n文章的静态资源,主要是图片,才是一个最耗流量和存储空间的东西。\n前一段时间经历了腾讯云 cos 对象存储被盗刷 的事件后,对于对象存储的使用也就越来越谨慎,今天终于狠下决心来把 Knowledge-Garden 这个仓库的所有包括图片在内的静态资源开始保存到另外一个 GitHub 仓库 PicKG,同时借助 Cloudflare Pages 来为图片提供访问链接。\n也尝试了一下 Cloudflare 的 R2 这个号称零出口费用的对象存储,免费额度很有吸引力,但目前 Cloudflare R2 还没能找到一个比较顺手的图片管理工具,例如阿里云的 oss-browser、腾讯云的 cos-browser。虽然尝试了一些折中的方案,如 Picx4R2,但还是不太满意。\n所以目前的解决方法就是 GitHub + PicX + Cloudflare Pages 进行组合,GitHub 单个仓库 5G 的存储空间应该应该也足够使用了,如果实在不够了再来考虑其他方案。', 'bodyHTML': '

使用 GitHub Discussions 写作文章大半年以来,越来越得心应手,最近起用了新的一个仓库,用于 Knowledge-Garden 静态资源的保存和使用。

\n\n

文章

\n

所有的文章都是以 markdown 的格式进行保存,实际上就一堆 text 文本,占用不了多少的空间。

\n

静态资源

\n

文章的静态资源,主要是图片,才是一个最耗流量和存储空间的东西。

\n

前一段时间经历了腾讯云 cos 对象存储被盗刷 的事件后,对于对象存储的使用也就越来越谨慎,今天终于狠下决心来把 Knowledge-Garden 这个仓库的所有包括图片在内的静态资源开始保存到另外一个 GitHub 仓库 PicKG,同时借助 Cloudflare Pages 来为图片提供访问链接。

\n

也尝试了一下 Cloudflare 的 R2 这个号称零出口费用的对象存储,免费额度很有吸引力,但目前 Cloudflare R2 还没能找到一个比较顺手的图片管理工具,例如阿里云的 oss-browser、腾讯云的 cos-browser。虽然尝试了一些折中的方案,如 Picx4R2,但还是不太满意。

\n

所以目前的解决方法就是 GitHub + PicX + Cloudflare Pages 进行组合,GitHub 单个仓库 5G 的存储空间应该应该也足够使用了,如果实在不够了再来考虑其他方案。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '部署 PicX 图床到 Vercel', 'number': 68, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/68', 'createdAt': '2024-04-22T03:29:53Z', 'lastEditedAt': '2024-05-28T01:50:54Z', 'updatedAt': '2024-05-28T01:50:54Z', 'body': '由于 [PicX](https://github.com/XPoet/picx) 自 v3.0 起,不再支持自由选择仓库和分支,统一使用内置的仓库和分支。所以出于自定义的仓库和分支使用需求,这里主要对 [PicX v2.0](https://github.com/XPoet/picx/tree/v2) 进行 Vercel 自定义部署。\r\n\r\n\r\n\r\n项目地址:https://github.com/XPoet/picx/tree/v2\r\n\r\n利用 PicX 图床,直接把图片托管到 GitHub 上去。至于安装,参考[子舒 Blog](https://zburu.com/)的《[安装一个基于 Github 的静态图床程序](https://zburu.com/blog/172.html/)》这两篇文章。可以把程序和图床直接托管在 GitHub 上,也可以把程序搭建在自己的服务器上,但是图片还是只能托管到 GitHub 上。PicX 图床不像简单图床和兰空图床,图片生成的链接可以是自己的域名链接,而因为图片是托管到 GitHub 上,所以 PicX 生成的图片外链接只能是 staticaly 和 cloudfalre 的 CDN 的外链。所以个人感觉也就没有必要再把程序上传到自己的服务器上了,直接使用 GitHub 不是更好嘛。\r\n\r\n## 操作步骤\r\n\r\n主要的操作步骤如下: \r\n\r\n- 1 个 GitHub 账号;\r\n- 1 个 Vercel 账号,可能需要科学上网环境;\r\n- Fork PicX v2 源码 (https://github.com/XPoet/picx/tree/v2) 到个人 GitHub 仓库;\r\n- 在 Vercel 新建项目,绑定个人 GitHub 仓库的 PicX v2 源码;Framework Preset 选择 "Vue.js";\r\n- 部署完成后为域名添加一条 CNAME 到 `cname-china.vercel-dns.com`。\r\n\r\n基于以上的步骤,个人成功部署的一个 PicX 站点,以供参考和使用:\r\n\r\n- https://github.com/shenweiyan/PicX\r\n- 链接1:\r\n- 链接2:\r\n\r\n![picx-weiyan-cc](https://kg.weiyan.cc/2024/05/picx-weiyan-cc.webp)', 'bodyText': '由于 PicX 自 v3.0 起,不再支持自由选择仓库和分支,统一使用内置的仓库和分支。所以出于自定义的仓库和分支使用需求,这里主要对 PicX v2.0 进行 Vercel 自定义部署。\n\n项目地址:https://github.com/XPoet/picx/tree/v2\n利用 PicX 图床,直接把图片托管到 GitHub 上去。至于安装,参考子舒 Blog的《安装一个基于 Github 的静态图床程序》这两篇文章。可以把程序和图床直接托管在 GitHub 上,也可以把程序搭建在自己的服务器上,但是图片还是只能托管到 GitHub 上。PicX 图床不像简单图床和兰空图床,图片生成的链接可以是自己的域名链接,而因为图片是托管到 GitHub 上,所以 PicX 生成的图片外链接只能是 staticaly 和 cloudfalre 的 CDN 的外链。所以个人感觉也就没有必要再把程序上传到自己的服务器上了,直接使用 GitHub 不是更好嘛。\n操作步骤\n主要的操作步骤如下:\n\n1 个 GitHub 账号;\n1 个 Vercel 账号,可能需要科学上网环境;\nFork PicX v2 源码 (https://github.com/XPoet/picx/tree/v2) 到个人 GitHub 仓库;\n在 Vercel 新建项目,绑定个人 GitHub 仓库的 PicX v2 源码;Framework Preset 选择 "Vue.js";\n部署完成后为域名添加一条 CNAME 到 cname-china.vercel-dns.com。\n\n基于以上的步骤,个人成功部署的一个 PicX 站点,以供参考和使用:\n\nhttps://github.com/shenweiyan/PicX\n链接1:https://v2picx.vercel.app/\n链接2:https://picx.weiyan.cc/', 'bodyHTML': '

由于 PicX 自 v3.0 起,不再支持自由选择仓库和分支,统一使用内置的仓库和分支。所以出于自定义的仓库和分支使用需求,这里主要对 PicX v2.0 进行 Vercel 自定义部署。

\n\n

项目地址:https://github.com/XPoet/picx/tree/v2

\n

利用 PicX 图床,直接把图片托管到 GitHub 上去。至于安装,参考子舒 Blog的《安装一个基于 Github 的静态图床程序》这两篇文章。可以把程序和图床直接托管在 GitHub 上,也可以把程序搭建在自己的服务器上,但是图片还是只能托管到 GitHub 上。PicX 图床不像简单图床和兰空图床,图片生成的链接可以是自己的域名链接,而因为图片是托管到 GitHub 上,所以 PicX 生成的图片外链接只能是 staticaly 和 cloudfalre 的 CDN 的外链。所以个人感觉也就没有必要再把程序上传到自己的服务器上了,直接使用 GitHub 不是更好嘛。

\n

操作步骤

\n

主要的操作步骤如下:

\n
    \n
  • 1 个 GitHub 账号;
  • \n
  • 1 个 Vercel 账号,可能需要科学上网环境;
  • \n
  • Fork PicX v2 源码 (https://github.com/XPoet/picx/tree/v2) 到个人 GitHub 仓库;
  • \n
  • 在 Vercel 新建项目,绑定个人 GitHub 仓库的 PicX v2 源码;Framework Preset 选择 "Vue.js";
  • \n
  • 部署完成后为域名添加一条 CNAME 到 cname-china.vercel-dns.com
  • \n
\n

基于以上的步骤,个人成功部署的一个 PicX 站点,以供参考和使用:

\n\n

picx-weiyan-cc

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '国内静态部署与托管平台', 'number': 67, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/67', 'createdAt': '2024-04-15T07:19:16Z', 'lastEditedAt': None, 'updatedAt': '2024-04-15T07:22:22Z', 'body': '[Gitee Pages](https://gitee.com/help/articles/4136/) 由于审查原因,基本上已经是名存实亡的状态了;之前勉强可以使用的 [Webbify](https://webify.cloudbase.net/) 现如今也变成了每月至少 15 块的购买时长模式。\r\n\r\n\r\n\r\n之前在《[越来越难用的国内代码托管平台](https://github.com/shenweiyan/Knowledge-Garden/discussions/56)》吐槽过一波国内所谓开源平台的状况,今天又发现除了代码平台外,原来静态部署的平台也走上了这一条路。\r\n\r\n[Gitee Pages](https://gitee.com/help/articles/4136/) 就不说了,懂得都懂。\r\n\r\n说一说腾讯云的 [Webbify](https://webify.cloudbase.net/)。今天 (2024年4月15) 上去想要部署一个新的站点,居然发现以前的 **"按量付费"** 计费模式已经消失,取而代之的是一个每月至少 15 块的购买时长模式。作为一个 2021 年就不再更新的产品,这样的收费模式真是让人瞬间欲望大减。\r\n![webify-price-15-pre-month.webp](https://static.weiyan.tech/2024/04/webify-price-15-pre-month.webp)\r\n\r\n回过头来看一看国外的 [Netlify](https://app.netlify.com/)、[Vercel](https://vercel.com/)、[Cloudflare Pages](https://www.cloudflare-cn.com/developer-platform/pages/),甚至是 GitHub Pages,再看一下国内的这些平台,真是一言难尽,除了先培养用户再收割,好像也没剩下什么了。\r\n', 'bodyText': 'Gitee Pages 由于审查原因,基本上已经是名存实亡的状态了;之前勉强可以使用的 Webbify 现如今也变成了每月至少 15 块的购买时长模式。\n\n之前在《越来越难用的国内代码托管平台》吐槽过一波国内所谓开源平台的状况,今天又发现除了代码平台外,原来静态部署的平台也走上了这一条路。\nGitee Pages 就不说了,懂得都懂。\n说一说腾讯云的 Webbify。今天 (2024年4月15) 上去想要部署一个新的站点,居然发现以前的 "按量付费" 计费模式已经消失,取而代之的是一个每月至少 15 块的购买时长模式。作为一个 2021 年就不再更新的产品,这样的收费模式真是让人瞬间欲望大减。\n\n回过头来看一看国外的 Netlify、Vercel、Cloudflare Pages,甚至是 GitHub Pages,再看一下国内的这些平台,真是一言难尽,除了先培养用户再收割,好像也没剩下什么了。', 'bodyHTML': '

Gitee Pages 由于审查原因,基本上已经是名存实亡的状态了;之前勉强可以使用的 Webbify 现如今也变成了每月至少 15 块的购买时长模式。

\n\n

之前在《越来越难用的国内代码托管平台》吐槽过一波国内所谓开源平台的状况,今天又发现除了代码平台外,原来静态部署的平台也走上了这一条路。

\n

Gitee Pages 就不说了,懂得都懂。

\n

说一说腾讯云的 Webbify。今天 (2024年4月15) 上去想要部署一个新的站点,居然发现以前的 "按量付费" 计费模式已经消失,取而代之的是一个每月至少 15 块的购买时长模式。作为一个 2021 年就不再更新的产品,这样的收费模式真是让人瞬间欲望大减。
\nwebify-price-15-pre-month.webp

\n

回过头来看一看国外的 NetlifyVercelCloudflare Pages,甚至是 GitHub Pages,再看一下国内的这些平台,真是一言难尽,除了先培养用户再收割,好像也没剩下什么了。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '备案接入信息与实际接入信息不符', 'number': 66, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/66', 'createdAt': '2024-04-11T07:09:00Z', 'lastEditedAt': '2024-04-11T07:11:25Z', 'updatedAt': '2024-04-11T07:11:25Z', 'body': '在阿里云注册且完成备案的域名,前两天收到了信息:如您的网站备案还要继续使用,请您务必于2024-04-18 09:05:39之前设置解析指向阿里云内地服务器且恢复该网站在阿里云内地节点服务器的正常访问。\r\n\r\n\r\n\r\n> 如您的网站备案还要继续使用,请您务必于2024-04-18 09:05:39之前设置解析指向阿里云内地服务器且恢复该网站在阿里云内地节点服务器的正常访问。若在规定时间内未完成整改,可能会导致备案信息被取消接入或被注销,影响您网站的正常访问;若您的备案域名解析IP地址已指向阿里云备案的内地节点(不含香港)服务器,且保持正常访问,请忽略此邮件。\r\n\r\n![beian-weiyan-cc.webp](https://static.weiyan.tech/2024/04/beian-weiyan-cc.webp)\r\n\r\n目前,参考知乎《[阿里云服务器备案域名会掉吗](https://zhuanlan.zhihu.com/p/516077564)》的方法 —— 先把目前 `weiyan.cc` 下的一到两个子域名增加一个 A 记录绑定到阿里云的 ECS 公网 IP,主域名继续按目前的要求通过 CNAME 绑定 [weiyan.netlify.app](https://weiyan.netlify.app)。\r\n\r\n再看看后续是否有影响。', 'bodyText': '在阿里云注册且完成备案的域名,前两天收到了信息:如您的网站备案还要继续使用,请您务必于2024-04-18 09:05:39之前设置解析指向阿里云内地服务器且恢复该网站在阿里云内地节点服务器的正常访问。\n\n\n如您的网站备案还要继续使用,请您务必于2024-04-18 09:05:39之前设置解析指向阿里云内地服务器且恢复该网站在阿里云内地节点服务器的正常访问。若在规定时间内未完成整改,可能会导致备案信息被取消接入或被注销,影响您网站的正常访问;若您的备案域名解析IP地址已指向阿里云备案的内地节点(不含香港)服务器,且保持正常访问,请忽略此邮件。\n\n\n目前,参考知乎《阿里云服务器备案域名会掉吗》的方法 —— 先把目前 weiyan.cc 下的一到两个子域名增加一个 A 记录绑定到阿里云的 ECS 公网 IP,主域名继续按目前的要求通过 CNAME 绑定 weiyan.netlify.app。\n再看看后续是否有影响。', 'bodyHTML': '

在阿里云注册且完成备案的域名,前两天收到了信息:如您的网站备案还要继续使用,请您务必于2024-04-18 09:05:39之前设置解析指向阿里云内地服务器且恢复该网站在阿里云内地节点服务器的正常访问。

\n\n
\n

如您的网站备案还要继续使用,请您务必于2024-04-18 09:05:39之前设置解析指向阿里云内地服务器且恢复该网站在阿里云内地节点服务器的正常访问。若在规定时间内未完成整改,可能会导致备案信息被取消接入或被注销,影响您网站的正常访问;若您的备案域名解析IP地址已指向阿里云备案的内地节点(不含香港)服务器,且保持正常访问,请忽略此邮件。

\n
\n

beian-weiyan-cc.webp

\n

目前,参考知乎《阿里云服务器备案域名会掉吗》的方法 —— 先把目前 weiyan.cc 下的一到两个子域名增加一个 A 记录绑定到阿里云的 ECS 公网 IP,主域名继续按目前的要求通过 CNAME 绑定 weiyan.netlify.app

\n

再看看后续是否有影响。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'RSS 订阅插件 mkdocs-rss-plugin 的一些问题', 'number': 65, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/65', 'createdAt': '2024-04-11T02:37:00Z', 'lastEditedAt': None, 'updatedAt': '2024-04-22T01:31:54Z', 'body': '聊一下 Mkdocs Material 的默认插件 [mkdocs-rss-plugin](https://github.com/Guts/mkdocs-rss-plugin) 在使用上的一些问题。\r\n\r\n\r\n\r\n对于 blog 插件,默认的 RSS 里边提供的地址有一部分会默认为目录链接(例如 `category` 和 `archive`),而非文章地址。\r\n\r\n![rss-item.webp](https://static.weiyan.tech/2024/04/rss-item.webp)\r\n\r\n针对这一种情况,需要使用 RSS 配置的 [`match_path`](https://guts.github.io/mkdocs-rss-plugin/configuration/#match_path-filter-pages-to-include-in-feed),即可解决:\r\n\r\n```\r\nplugins:\r\n - rss:\r\n match_path: "(blog/posts|flinks|galaxy|message|note|readme|tech|yuque)/.*"\r\n date_from_meta:\r\n as_creation: date\r\n categories:\r\n - categories\r\n - tags\r\n```\r\n', 'bodyText': '聊一下 Mkdocs Material 的默认插件 mkdocs-rss-plugin 在使用上的一些问题。\n\n对于 blog 插件,默认的 RSS 里边提供的地址有一部分会默认为目录链接(例如 category 和 archive),而非文章地址。\n\n针对这一种情况,需要使用 RSS 配置的 match_path,即可解决:\nplugins:\n - rss:\n match_path: "(blog/posts|flinks|galaxy|message|note|readme|tech|yuque)/.*"\n date_from_meta:\n as_creation: date\n categories:\n - categories\n - tags', 'bodyHTML': '

聊一下 Mkdocs Material 的默认插件 mkdocs-rss-plugin 在使用上的一些问题。

\n\n

对于 blog 插件,默认的 RSS 里边提供的地址有一部分会默认为目录链接(例如 categoryarchive),而非文章地址。

\n

rss-item.webp

\n

针对这一种情况,需要使用 RSS 配置的 match_path,即可解决:

\n
plugins:\n  - rss:\n      match_path: "(blog/posts|flinks|galaxy|message|note|readme|tech|yuque)/.*"\n      date_from_meta:\n        as_creation: date\n      categories:\n        - categories\n        - tags\n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': [{'name': 'mkdocs'}]}, 'comments': {'nodes': [{'body': '终于修复了,之前一直有问题。', 'author': {'login': 'Jaaayden'}}]}}, {'title': '无趣的人', 'number': 64, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/64', 'createdAt': '2024-04-07T07:29:06Z', 'lastEditedAt': None, 'updatedAt': '2024-04-07T07:29:07Z', 'body': '有趣的灵魂万里挑一,好看的皮囊千篇一律。\r\n\r\n\r\n\r\n活得通透的人 ,没有特别想维持的关系 ,也没有特别想要的东西 ,走近的人不抗拒 ,离开的人不强留 ,就连吃亏也懒得计较。\r\n\r\n从统计上来看,成年后还能重塑自我的人太罕见了。年纪越大就越相信命运,其中最大的一个原因就是理解人的改变之难。意图改变不如早早学会接纳。', 'bodyText': '有趣的灵魂万里挑一,好看的皮囊千篇一律。\n\n活得通透的人 ,没有特别想维持的关系 ,也没有特别想要的东西 ,走近的人不抗拒 ,离开的人不强留 ,就连吃亏也懒得计较。\n从统计上来看,成年后还能重塑自我的人太罕见了。年纪越大就越相信命运,其中最大的一个原因就是理解人的改变之难。意图改变不如早早学会接纳。', 'bodyHTML': '

有趣的灵魂万里挑一,好看的皮囊千篇一律。

\n\n

活得通透的人 ,没有特别想维持的关系 ,也没有特别想要的东西 ,走近的人不抗拒 ,离开的人不强留 ,就连吃亏也懒得计较。

\n

从统计上来看,成年后还能重塑自我的人太罕见了。年纪越大就越相信命运,其中最大的一个原因就是理解人的改变之难。意图改变不如早早学会接纳。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '腾讯云 cos 也被盗刷了', 'number': 63, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/63', 'createdAt': '2024-03-29T07:07:37Z', 'lastEditedAt': '2024-04-03T01:31:55Z', 'updatedAt': '2024-04-03T01:31:56Z', 'body': '我的 [WebStack-Hugo](https://bioit.top/) 个人导航站点最开始用的是腾讯云的 cos 对象存储作为所有图片的存储和访问,在 2024 年 3 月底的时候收到腾讯云的通知说 200 万次的标准存储请求已经用掉了 180 多万次。\r\n\r\n\r\n\r\n![cos-warning.webp](https://static.weiyan.tech/2024/03/cos-warning.webp)\r\n\r\n收到信息吓了一跳,心想我这一个小破网站不至于这么多的请求吧,肯定被攻击盗刷了。加上之前在网络上看到的阿里云/腾讯云对象存储被刷爆的新闻还历历在目,于是赶紧的上去腾讯云一看发现一天的读写请求居然达到了 25 万多次!\r\n\r\n![cos-y-requests](https://static.weiyan.tech/2024/03/cos-y-requests.webp)\r\n\r\n虽然之前一直设置了防盗链,但是一直允许着 **"空 referer"**,这无疑是一个巨大的漏洞,参考 《[COS被流量盗刷了](https://zhuanlan.zhihu.com/p/660308000)》 的经历,第一时间就把这个 **"空 referer"** 设置为了 **"拒绝"**,并开启了日志。\r\n\r\n果不其然,一段时间过后从生成的日志文件,发现了这样的一个网址:。\r\n![123-wqydl-get](https://static.weiyan.tech/2024/03/123-wqydl-get.webp)\r\n\r\n这个网站一直在请求获取个人 cos 内的 `/webstack/logos/default.webp` 这个图片!为了安全起见,又赶紧第一时间把这个网站加入了黑名单,并且把对应的 cos 权限设置成了 **"私有读写"**。\r\n\r\n但是从源源不断产生的日志可以看到这个恶心的网站还一直不依不饶在每隔几分钟就执行一堆读取请求!\r\n![get-requests-by-time.webp](https://static.weiyan.tech/2024/03/get-requests-by-time.webp)\r\n\r\n但幸运的是这些请求现在都 **"AccessDenied"** 了,但对它的一些后续可能的动作也很是好奇,在持续观察中。\r\n![cos-access-denied.webp](https://static.weiyan.tech/2024/03/cos-access-denied.webp)\r\n\r\n![cos-log.png](https://static.weiyan.tech/2024/03/cos-log.png)\r\n\r\n![cos-safe.png](https://static.weiyan.tech/2024/03/cos-safe.png)\r\n\r\n终于,第二天的晚上终于在他们的官网联系上了对应的客服,他们把相应的网站停掉后一切又回归正常。 \r\n![cos-package-free.webp](https://static.weiyan.tech/2024/04/cos-package-free.webp)\r\n\r\n最后,以此为鉴,希望大家在提供公共资源的时候擦亮眼睛,避免踩坑。', 'bodyText': '我的 WebStack-Hugo 个人导航站点最开始用的是腾讯云的 cos 对象存储作为所有图片的存储和访问,在 2024 年 3 月底的时候收到腾讯云的通知说 200 万次的标准存储请求已经用掉了 180 多万次。\n\n\n收到信息吓了一跳,心想我这一个小破网站不至于这么多的请求吧,肯定被攻击盗刷了。加上之前在网络上看到的阿里云/腾讯云对象存储被刷爆的新闻还历历在目,于是赶紧的上去腾讯云一看发现一天的读写请求居然达到了 25 万多次!\n\n虽然之前一直设置了防盗链,但是一直允许着 "空 referer",这无疑是一个巨大的漏洞,参考 《COS被流量盗刷了》 的经历,第一时间就把这个 "空 referer" 设置为了 "拒绝",并开启了日志。\n果不其然,一段时间过后从生成的日志文件,发现了这样的一个网址:https://123.wqydl.cn/。\n\n这个网站一直在请求获取个人 cos 内的 /webstack/logos/default.webp 这个图片!为了安全起见,又赶紧第一时间把这个网站加入了黑名单,并且把对应的 cos 权限设置成了 "私有读写"。\n但是从源源不断产生的日志可以看到这个恶心的网站还一直不依不饶在每隔几分钟就执行一堆读取请求!\n\n但幸运的是这些请求现在都 "AccessDenied" 了,但对它的一些后续可能的动作也很是好奇,在持续观察中。\n\n\n\n终于,第二天的晚上终于在他们的官网联系上了对应的客服,他们把相应的网站停掉后一切又回归正常。\n\n最后,以此为鉴,希望大家在提供公共资源的时候擦亮眼睛,避免踩坑。', 'bodyHTML': '

我的 WebStack-Hugo 个人导航站点最开始用的是腾讯云的 cos 对象存储作为所有图片的存储和访问,在 2024 年 3 月底的时候收到腾讯云的通知说 200 万次的标准存储请求已经用掉了 180 多万次。

\n\n

cos-warning.webp

\n

收到信息吓了一跳,心想我这一个小破网站不至于这么多的请求吧,肯定被攻击盗刷了。加上之前在网络上看到的阿里云/腾讯云对象存储被刷爆的新闻还历历在目,于是赶紧的上去腾讯云一看发现一天的读写请求居然达到了 25 万多次!

\n

cos-y-requests

\n

虽然之前一直设置了防盗链,但是一直允许着 "空 referer",这无疑是一个巨大的漏洞,参考 《COS被流量盗刷了》 的经历,第一时间就把这个 "空 referer" 设置为了 "拒绝",并开启了日志。

\n

果不其然,一段时间过后从生成的日志文件,发现了这样的一个网址:https://123.wqydl.cn/
\n123-wqydl-get

\n

这个网站一直在请求获取个人 cos 内的 /webstack/logos/default.webp 这个图片!为了安全起见,又赶紧第一时间把这个网站加入了黑名单,并且把对应的 cos 权限设置成了 "私有读写"

\n

但是从源源不断产生的日志可以看到这个恶心的网站还一直不依不饶在每隔几分钟就执行一堆读取请求!
\nget-requests-by-time.webp

\n

但幸运的是这些请求现在都 "AccessDenied" 了,但对它的一些后续可能的动作也很是好奇,在持续观察中。
\ncos-access-denied.webp

\n

cos-log.png

\n

cos-safe.png

\n

终于,第二天的晚上终于在他们的官网联系上了对应的客服,他们把相应的网站停掉后一切又回归正常。
\ncos-package-free.webp

\n

最后,以此为鉴,希望大家在提供公共资源的时候擦亮眼睛,避免踩坑。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '图床管理与使用', 'number': 62, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/62', 'createdAt': '2024-03-27T07:48:45Z', 'lastEditedAt': '2024-03-28T05:02:32Z', 'updatedAt': '2024-03-28T05:02:32Z', 'body': '随着博客和其他一些站点多了起来,日积月累的访问越来越觉得腾讯云 cos 和阿里云 oss 是远远不够的,于是开始想着寻找可以一劳永逸的图床管理和使用替代者。\r\n\r\n\r\n\r\nGitHub 的图床虽然不错,但如果文件越来越多,终究不是一个很好的解决方案。\r\n\r\nCloudflare R2 目前看来是个不错的选项,但是图片的上传、删除和日常管理目前还没有找到一个比较顺手的工具。目前在用的一个 [Picx4R2](https://github.com/shenweiyan/Picx4R2/) 还有一些不太满意的地方,即上传的图片无法保留原始的文件名!—— 不过幸运的是借助百度文心一言终于把保留原始文件名的这个问题给解决了。', 'bodyText': '随着博客和其他一些站点多了起来,日积月累的访问越来越觉得腾讯云 cos 和阿里云 oss 是远远不够的,于是开始想着寻找可以一劳永逸的图床管理和使用替代者。\n\nGitHub 的图床虽然不错,但如果文件越来越多,终究不是一个很好的解决方案。\nCloudflare R2 目前看来是个不错的选项,但是图片的上传、删除和日常管理目前还没有找到一个比较顺手的工具。目前在用的一个 Picx4R2 还有一些不太满意的地方,即上传的图片无法保留原始的文件名!—— 不过幸运的是借助百度文心一言终于把保留原始文件名的这个问题给解决了。', 'bodyHTML': '

随着博客和其他一些站点多了起来,日积月累的访问越来越觉得腾讯云 cos 和阿里云 oss 是远远不够的,于是开始想着寻找可以一劳永逸的图床管理和使用替代者。

\n\n

GitHub 的图床虽然不错,但如果文件越来越多,终究不是一个很好的解决方案。

\n

Cloudflare R2 目前看来是个不错的选项,但是图片的上传、删除和日常管理目前还没有找到一个比较顺手的工具。目前在用的一个 Picx4R2 还有一些不太满意的地方,即上传的图片无法保留原始的文件名!—— 不过幸运的是借助百度文心一言终于把保留原始文件名的这个问题给解决了。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'Python 里面没 if 也能用 else', 'number': 61, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/61', 'createdAt': '2024-03-21T01:47:26Z', 'lastEditedAt': '2024-03-22T01:21:34Z', 'updatedAt': '2024-03-22T01:21:34Z', 'body': '> 这是来自于 [Yang Zhou](https://twitter.com/YangZhou1993) 发表在 [Medium](https://medium.com/techtofreedom/beyond-if-else-leveraging-pythons-versatile-else-statements-9ac260dac102) 的一篇文章 《[Beyond If-Else: Leveraging Python’s Versatile “Else” Statements](https://medium.com/techtofreedom/beyond-if-else-leveraging-pythons-versatile-else-statements-9ac260dac102)》,作者觉得挺有意思的,拿过来简单翻译了一下在这里分享给大家。\r\n\r\n\r\n\r\n当我们说到 "else",必须先有 "if"。\r\n\r\n这对于许多编程语言来说都是正确的,但对于 Python 来说却不然。\r\n\r\nPython 的 else 语句比我们想象的更通用。\r\n\r\n从循环后的 "else" 到 try- except 块后的 "else",本文将探讨 else 语句鲜为人知的功能。\r\n\r\n我们不一定需要在生产中使用这些技巧,尤其是当我们的同事还不知道它们时,但仅仅意识到它们的存在就可以让我们再次感受到 Python 的灵活性和多功能性。\r\n\r\n## 1. While-Else 结构\r\n\r\n在 Python 中, `while` 循环可以与 `else` 块配对。当且仅当循环正常完成时,`else` 块才会执行,这意味着它不会通过 `break` 语句终止。\r\n\r\n换句话说,如果 `while` 循环被 `break` 终止,则 `else` 块将不会被执行。\r\n```python\r\nleaders = ["Elon", "Tim", "Warren"]\r\ni = 0\r\nwhile i < len(leaders):\r\n if leaders[i] == "Yang":\r\n print("Yang is a leader!")\r\n break\r\n i += 1\r\nelse:\r\n print("Not found Yang!")\r\n\r\n# Not found Yang!\r\n```\r\n\r\n如上面的示例所示, `while` 循环迭代 `leaders` 列表,搜索领导者 "Yang"。不幸的是,"Yang" 并不是该名单中真正的领导者。所以 `break` 语句没有被执行。因此,`else` 语句下的代码就被执行了。\r\n\r\n`else` 语句的这种意外用法使我们无需添加额外的标志变量来标记循环是否被破坏。这样我们的 Python 程序就可以精简一些了。\r\n\r\n## 2. 带有 For 循环的 Else 语句\r\n\r\nFor 循环和 `while` 循环是编程的孪生兄弟。如果我们可以在 while 循环中利用 else 语句的多功能性,那么毫无疑问它可以用于 for 循环。\r\n\r\n这个想法是完全相同的: \r\n\r\n> The "else" block only executes when there is no break in the for loop. \r\n> "else" 块仅在 for 循环中没有中断时执行。 \r\n\r\n让我们用 for 循环重写前面的示例:\r\n```python\r\nleaders = ["Elon", "Tim", "Warren"]\r\n\r\nfor i in leaders:\r\n if i == "Yang":\r\n print("Yang is a leader!")\r\n break\r\nelse:\r\n print("Not found Yang!")\r\n\r\n# Not found Yang!\r\n```\r\n\r\n代码更简洁了,不是吗?你能用其他编程语言做到这一点吗?\r\n\r\n## 3. 使用 Else 语句进行异常处理\r\n\r\n异常处理是编写健壮且无错误的代码的一项重要技术。\r\n\r\n在 Python 中,整个异常处理代码块的结构应该如下:\r\n```python\r\ntry:\r\n # Code that might raise an exception\r\nexcept SomeException:\r\n # Code that runs if the try block raised \'SomeException\'\r\nelse:\r\n # Code that runs if the try block did NOT raise any exceptions\r\nfinally:\r\n # Code that always runs no matter what, often for cleanup\r\n```\r\n\r\n除了 `try` 块之外,所有其他部分都是可选的。\r\n\r\n当 `try` 块未引发异常时, `else` 块就会执行。这是放置仅当 `try` 块成功且无异常时才运行的代码的好地方。这对于阐明代码的意图并防止 `except` 块意外捕获非常有用。\r\n\r\n例如,以下程序实现了一个非常简单的除法函数:\r\n```python\r\ndef divide(x, y):\r\n try:\r\n result = x / y\r\n except ZeroDivisionError:\r\n print("Error: Division by zero.")\r\n else:\r\n print(f"Result is {result}")\r\n finally:\r\n print("Executing finally clause.")\r\n```\r\n\r\n如果没有遇到 `ZeroDivisionError`,结果如下:\r\n\r\n```python\r\ndivide(2077, 1)\r\n# Result is 2077.0\r\n# Executing finally clause.\r\n```\r\n\r\n当然,如果满足定义的异常,则会打印相关的 `Error` 消息:\r\n```python\r\ndivide(2077, 0)\r\n# Error: Division by zero.\r\n# Executing finally clause.\r\n```\r\n\r\n## 要点总结\r\n\r\n在 Python 中,else 语句不一定位于 if 语句之后。\r\n\r\n它还有三个额外但鲜为人知的用途: \r\n\r\n- while-else 循环 \r\n- for-else 循环 \r\n- 使用 else 块进行异常处理 \r\n\r\n但是,我不建议您在生产中频繁应用它们,因为使用鲜为人知的功能可能会降低可读性并使您的同事感到困惑。但理解并随意应用它们会给你的同事留下深刻的印象,并巩固你作为 "Python 大师" 的地位。 😎', 'bodyText': '这是来自于 Yang Zhou 发表在 Medium 的一篇文章 《Beyond If-Else: Leveraging Python’s Versatile “Else” Statements》,作者觉得挺有意思的,拿过来简单翻译了一下在这里分享给大家。\n\n\n当我们说到 "else",必须先有 "if"。\n这对于许多编程语言来说都是正确的,但对于 Python 来说却不然。\nPython 的 else 语句比我们想象的更通用。\n从循环后的 "else" 到 try- except 块后的 "else",本文将探讨 else 语句鲜为人知的功能。\n我们不一定需要在生产中使用这些技巧,尤其是当我们的同事还不知道它们时,但仅仅意识到它们的存在就可以让我们再次感受到 Python 的灵活性和多功能性。\n1. While-Else 结构\n在 Python 中, while 循环可以与 else 块配对。当且仅当循环正常完成时,else 块才会执行,这意味着它不会通过 break 语句终止。\n换句话说,如果 while 循环被 break 终止,则 else 块将不会被执行。\nleaders = ["Elon", "Tim", "Warren"]\ni = 0\nwhile i < len(leaders):\n if leaders[i] == "Yang":\n print("Yang is a leader!")\n break\n i += 1\nelse:\n print("Not found Yang!")\n\n# Not found Yang!\n如上面的示例所示, while 循环迭代 leaders 列表,搜索领导者 "Yang"。不幸的是,"Yang" 并不是该名单中真正的领导者。所以 break 语句没有被执行。因此,else 语句下的代码就被执行了。\nelse 语句的这种意外用法使我们无需添加额外的标志变量来标记循环是否被破坏。这样我们的 Python 程序就可以精简一些了。\n2. 带有 For 循环的 Else 语句\nFor 循环和 while 循环是编程的孪生兄弟。如果我们可以在 while 循环中利用 else 语句的多功能性,那么毫无疑问它可以用于 for 循环。\n这个想法是完全相同的:\n\nThe "else" block only executes when there is no break in the for loop.\n"else" 块仅在 for 循环中没有中断时执行。\n\n让我们用 for 循环重写前面的示例:\nleaders = ["Elon", "Tim", "Warren"]\n\nfor i in leaders:\n if i == "Yang":\n print("Yang is a leader!")\n break\nelse:\n print("Not found Yang!")\n\n# Not found Yang!\n代码更简洁了,不是吗?你能用其他编程语言做到这一点吗?\n3. 使用 Else 语句进行异常处理\n异常处理是编写健壮且无错误的代码的一项重要技术。\n在 Python 中,整个异常处理代码块的结构应该如下:\ntry:\n # Code that might raise an exception\nexcept SomeException:\n # Code that runs if the try block raised \'SomeException\'\nelse:\n # Code that runs if the try block did NOT raise any exceptions\nfinally:\n # Code that always runs no matter what, often for cleanup\n除了 try 块之外,所有其他部分都是可选的。\n当 try 块未引发异常时, else 块就会执行。这是放置仅当 try 块成功且无异常时才运行的代码的好地方。这对于阐明代码的意图并防止 except 块意外捕获非常有用。\n例如,以下程序实现了一个非常简单的除法函数:\ndef divide(x, y):\n try:\n result = x / y\n except ZeroDivisionError:\n print("Error: Division by zero.")\n else:\n print(f"Result is {result}")\n finally:\n print("Executing finally clause.")\n如果没有遇到 ZeroDivisionError,结果如下:\ndivide(2077, 1)\n# Result is 2077.0\n# Executing finally clause.\n当然,如果满足定义的异常,则会打印相关的 Error 消息:\ndivide(2077, 0)\n# Error: Division by zero.\n# Executing finally clause.\n要点总结\n在 Python 中,else 语句不一定位于 if 语句之后。\n它还有三个额外但鲜为人知的用途:\n\nwhile-else 循环\nfor-else 循环\n使用 else 块进行异常处理\n\n但是,我不建议您在生产中频繁应用它们,因为使用鲜为人知的功能可能会降低可读性并使您的同事感到困惑。但理解并随意应用它们会给你的同事留下深刻的印象,并巩固你作为 "Python 大师" 的地位。 😎', 'bodyHTML': '
\n

这是来自于 Yang Zhou 发表在 Medium 的一篇文章 《Beyond If-Else: Leveraging Python’s Versatile “Else” Statements》,作者觉得挺有意思的,拿过来简单翻译了一下在这里分享给大家。

\n
\n\n

当我们说到 "else",必须先有 "if"。

\n

这对于许多编程语言来说都是正确的,但对于 Python 来说却不然。

\n

Python 的 else 语句比我们想象的更通用。

\n

从循环后的 "else" 到 try- except 块后的 "else",本文将探讨 else 语句鲜为人知的功能。

\n

我们不一定需要在生产中使用这些技巧,尤其是当我们的同事还不知道它们时,但仅仅意识到它们的存在就可以让我们再次感受到 Python 的灵活性和多功能性。

\n

1. While-Else 结构

\n

在 Python 中, while 循环可以与 else 块配对。当且仅当循环正常完成时,else 块才会执行,这意味着它不会通过 break 语句终止。

\n

换句话说,如果 while 循环被 break 终止,则 else 块将不会被执行。

\n
leaders = ["Elon", "Tim", "Warren"]\ni = 0\nwhile i < len(leaders):\n    if leaders[i] == "Yang":\n        print("Yang is a leader!")\n        break\n    i += 1\nelse:\n    print("Not found Yang!")\n\n# Not found Yang!
\n

如上面的示例所示, while 循环迭代 leaders 列表,搜索领导者 "Yang"。不幸的是,"Yang" 并不是该名单中真正的领导者。所以 break 语句没有被执行。因此,else 语句下的代码就被执行了。

\n

else 语句的这种意外用法使我们无需添加额外的标志变量来标记循环是否被破坏。这样我们的 Python 程序就可以精简一些了。

\n

2. 带有 For 循环的 Else 语句

\n

For 循环和 while 循环是编程的孪生兄弟。如果我们可以在 while 循环中利用 else 语句的多功能性,那么毫无疑问它可以用于 for 循环。

\n

这个想法是完全相同的:

\n
\n

The "else" block only executes when there is no break in the for loop.
\n"else" 块仅在 for 循环中没有中断时执行。

\n
\n

让我们用 for 循环重写前面的示例:

\n
leaders = ["Elon", "Tim", "Warren"]\n\nfor i in leaders:\n    if i == "Yang":\n        print("Yang is a leader!")\n        break\nelse:\n    print("Not found Yang!")\n\n# Not found Yang!
\n

代码更简洁了,不是吗?你能用其他编程语言做到这一点吗?

\n

3. 使用 Else 语句进行异常处理

\n

异常处理是编写健壮且无错误的代码的一项重要技术。

\n

在 Python 中,整个异常处理代码块的结构应该如下:

\n
try:\n    # Code that might raise an exception\nexcept SomeException:\n    # Code that runs if the try block raised \'SomeException\'\nelse:\n    # Code that runs if the try block did NOT raise any exceptions\nfinally:\n    # Code that always runs no matter what, often for cleanup
\n

除了 try 块之外,所有其他部分都是可选的。

\n

try 块未引发异常时, else 块就会执行。这是放置仅当 try 块成功且无异常时才运行的代码的好地方。这对于阐明代码的意图并防止 except 块意外捕获非常有用。

\n

例如,以下程序实现了一个非常简单的除法函数:

\n
def divide(x, y):\n    try:\n        result = x / y\n    except ZeroDivisionError:\n        print("Error: Division by zero.")\n    else:\n        print(f"Result is {result}")\n    finally:\n        print("Executing finally clause.")
\n

如果没有遇到 ZeroDivisionError,结果如下:

\n
divide(2077, 1)\n# Result is 2077.0\n# Executing finally clause.
\n

当然,如果满足定义的异常,则会打印相关的 Error 消息:

\n
divide(2077, 0)\n# Error: Division by zero.\n# Executing finally clause.
\n

要点总结

\n

在 Python 中,else 语句不一定位于 if 语句之后。

\n

它还有三个额外但鲜为人知的用途:

\n
    \n
  • while-else 循环
  • \n
  • for-else 循环
  • \n
  • 使用 else 块进行异常处理
  • \n
\n

但是,我不建议您在生产中频繁应用它们,因为使用鲜为人知的功能可能会降低可读性并使您的同事感到困惑。但理解并随意应用它们会给你的同事留下深刻的印象,并巩固你作为 "Python 大师" 的地位。 😎

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.2-编程'}, 'labels': {'nodes': [{'name': '翻译'}, {'name': '1.2.3-Python'}]}, 'comments': {'nodes': []}}, {'title': 'RockyLinux 9 基础配置与使用', 'number': 60, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/60', 'createdAt': '2024-03-08T02:24:12Z', 'lastEditedAt': '2024-10-31T02:14:48Z', 'updatedAt': '2024-10-31T02:14:48Z', 'body': '今天终于在阿里云入手了一台 2核(vCPU)+ 2GiB + 3Mbps 的 ECS,安装了最新的 Rocky Linux release 9.3 (Blue Onyx),记录一下开箱后的一些基础配置。\r\n\r\n\r\n\r\n![aliyun-99-plan](https://shub.weiyan.tech/kgarden/2024/03/aliyun-99-plan.png)\r\n\r\n## Hostname\r\n```\r\n[root@r0sasd1bQi ~]# hostnamectl # 查看一下当前主机名的情况\r\n[root@r0sasd1bQi ~]# hostnamectl set-hostname shen-server --static\r\n[root@r0sasd1bQi ~]# hostnamectl status\r\n[root@r0sasd1bQi ~]# reboot now # 重启服务器\r\n```\r\n\r\n## 创建新用户\r\n\r\n使用 `adduser` 命令将新用户添加到系统中:\r\n```bash\r\nadduser shenweiyan # 创建新用户\r\npasswd shenweiyan # 修改密码\r\n```\r\n\r\n## 用户添加超级权限\r\n\r\n把 `shenweiyan` 用户添加超级权限(`/etc/sudoers`):\r\n```\r\nshenweiyan ALL=(ALL) NOPASSWD: ALL\r\n```\r\n\r\n## 自定义快捷方式\r\n\r\n在 `~/.bashrc` 最后新增一下用户自定义的快捷方式。\r\n\r\n```\r\n# User Specific Alias\r\nalias disp=\'display\'\r\nalias rm=\'rm -i\'\r\nalias la=\'ls -al\'\r\nalias ll=\'ls -lh\'\r\nalias le=\'less -S\'\r\n\r\n# Custom History setting\r\n# HISTFILESIZE 定义了在 .bash_history 中保存命令的记录总数\r\nHISTFILESIZE=3000000\r\n# HISTSIZE 定义了 history 命令输出的记录数\r\nHISTSIZE=3000\r\n# 定义 History 输出格式\r\nexport HISTTIMEFORMAT=\'%F %T \'\r\n# 使用 HISTCONTROL 从命令历史中剔除连续重复的条目\r\nHISTCONTROL=ignoredups\r\n# 将 bash 内存中历史命令追加到 .bash_history 历史命令文件中, 默认只有退出 shell 是才会保存\r\nPROMPT_COMMAND="history -a"\r\n\r\n# Login Style\r\nPS1=\'\\033[35;1m\\u@\\h \\[\\e[m\\]\\t \\[\\033[36;1m\\]$(pwd) \\n$ \\[\\e[m\\]\'\r\nclear;\r\n```\r\n\r\n## epel-release\r\n\r\n> 企业版 Linux 附加软件包(Extra Packages for Enterprise Linux,以下简称 EPEL)是一个 Fedora 特别兴趣小组,用以创建、维护以及管理针对企业版 Linux 的一个高质量附加软件包集,面向的对象包括但不限于 [红帽企业版 Linux (RHEL)](https://fedoraproject.org/wiki/Red_Hat_Enterprise_Linux/zh-cn)、 CentOS、Scientific Linux (SL)、Oracle Linux (OL) 。\r\n> \r\n> 参考:[EPEL/zh-cn - Fedora Project Wiki](https://fedoraproject.org/wiki/EPEL/zh-cn)\r\n\r\n```bash\r\n# 下面两个命令都可以安装\r\nsudo dnf install epel-release\r\nsudo dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm\r\n```\r\n\r\n## Htop 和 Btop\r\n\r\n[Htop](https://htop.dev/) 是一个基于 C 编写的跨平台的交互式流程查看器,`htop` 是 `top` 的一个增强替代品,提供了更加友好的用户界面和更多的功能,相比系统自带的 `top` 更加直观好用。 \r\n\r\n```bash\r\nsudo dnf install htop\r\n```\r\n\r\n`btop` 也是一个改进版的 Linux top 命令,这个命令不仅列出了各种系统使用情况,包括内存、磁盘、网络和进程,而且还允许与鼠标互动。即使是在服务器安装上,你也可以在 `btop` 上指指点点,以树形方式查看进程,隐藏或显示某些显示,并访问选项菜单,在那里你可以调整显示的外观和感觉。\r\n```bash\r\nsudo dnf install btop\r\n```\r\n\r\n## Docker 安装与使用\r\n\r\n主要参考《[How To Install and Use Docker on Rocky Linux 9](https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-rocky-linux-9)》,具体步骤如下: \r\n\r\n- add the official Docker repository\r\n ```bash\r\n sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo\r\n ```\r\n\r\n- install Docker\r\n ```bash\r\n sudo dnf install docker-ce docker-ce-cli containerd.io\r\n ```\r\n\r\n- start the Docker daemon\r\n ```bash\r\n sudo systemctl start docker\r\n ```\r\n\r\n- Verify that it’s running\r\n ```bash\r\n sudo systemctl status docker\r\n ```\r\n ```\r\n Output\r\n ● docker.service - Docker Application Container Engine\r\n Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)\r\n Active: active (running) since Sun 2016-05-01 06:53:52 CDT; 1 weeks 3 days ago\r\n Docs: https://docs.docker.com\r\n Main PID: 749 (docker)\r\n ```\r\n\r\n- make sure it starts at every server reboot\r\n ```bash\r\n sudo systemctl enable docker\r\n ```\r\n\r\n- 配置非 root 用户使用 Docker\r\n ```bash\r\n sudo usermod -aG docker username\r\n newgrp docker #更新docker用户组\r\n ```', 'bodyText': '今天终于在阿里云入手了一台 2核(vCPU)+ 2GiB + 3Mbps 的 ECS,安装了最新的 Rocky Linux release 9.3 (Blue Onyx),记录一下开箱后的一些基础配置。\n\n\nHostname\n[root@r0sasd1bQi ~]# hostnamectl # 查看一下当前主机名的情况\n[root@r0sasd1bQi ~]# hostnamectl set-hostname shen-server --static\n[root@r0sasd1bQi ~]# hostnamectl status\n[root@r0sasd1bQi ~]# reboot now # 重启服务器\n\n创建新用户\n使用 adduser 命令将新用户添加到系统中:\nadduser shenweiyan # 创建新用户\npasswd shenweiyan # 修改密码\n用户添加超级权限\n把 shenweiyan 用户添加超级权限(/etc/sudoers):\nshenweiyan ALL=(ALL) NOPASSWD: ALL\n\n自定义快捷方式\n在 ~/.bashrc 最后新增一下用户自定义的快捷方式。\n# User Specific Alias\nalias disp=\'display\'\nalias rm=\'rm -i\'\nalias la=\'ls -al\'\nalias ll=\'ls -lh\'\nalias le=\'less -S\'\n\n# Custom History setting\n# HISTFILESIZE 定义了在 .bash_history 中保存命令的记录总数\nHISTFILESIZE=3000000\n# HISTSIZE 定义了 history 命令输出的记录数\nHISTSIZE=3000\n# 定义 History 输出格式\nexport HISTTIMEFORMAT=\'%F %T \'\n# 使用 HISTCONTROL 从命令历史中剔除连续重复的条目\nHISTCONTROL=ignoredups\n# 将 bash 内存中历史命令追加到 .bash_history 历史命令文件中, 默认只有退出 shell 是才会保存\nPROMPT_COMMAND="history -a"\n\n# Login Style\nPS1=\'\\033[35;1m\\u@\\h \\[\\e[m\\]\\t \\[\\033[36;1m\\]$(pwd) \\n$ \\[\\e[m\\]\'\nclear;\n\nepel-release\n\n企业版 Linux 附加软件包(Extra Packages for Enterprise Linux,以下简称 EPEL)是一个 Fedora 特别兴趣小组,用以创建、维护以及管理针对企业版 Linux 的一个高质量附加软件包集,面向的对象包括但不限于 红帽企业版 Linux (RHEL)、 CentOS、Scientific Linux (SL)、Oracle Linux (OL) 。\n参考:EPEL/zh-cn - Fedora Project Wiki\n\n# 下面两个命令都可以安装\nsudo dnf install epel-release\nsudo dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm\nHtop 和 Btop\nHtop 是一个基于 C 编写的跨平台的交互式流程查看器,htop 是 top 的一个增强替代品,提供了更加友好的用户界面和更多的功能,相比系统自带的 top 更加直观好用。\nsudo dnf install htop\nbtop 也是一个改进版的 Linux top 命令,这个命令不仅列出了各种系统使用情况,包括内存、磁盘、网络和进程,而且还允许与鼠标互动。即使是在服务器安装上,你也可以在 btop 上指指点点,以树形方式查看进程,隐藏或显示某些显示,并访问选项菜单,在那里你可以调整显示的外观和感觉。\nsudo dnf install btop\nDocker 安装与使用\n主要参考《How To Install and Use Docker on Rocky Linux 9》,具体步骤如下:\n\n\nadd the official Docker repository\nsudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo\n\n\ninstall Docker\nsudo dnf install docker-ce docker-ce-cli containerd.io\n\n\nstart the Docker daemon\nsudo systemctl start docker\n\n\nVerify that it’s running\nsudo systemctl status docker\nOutput\n● docker.service - Docker Application Container Engine\n Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)\n Active: active (running) since Sun 2016-05-01 06:53:52 CDT; 1 weeks 3 days ago\n Docs: https://docs.docker.com\n Main PID: 749 (docker)\n\n\n\nmake sure it starts at every server reboot\nsudo systemctl enable docker\n\n\n配置非 root 用户使用 Docker\nsudo usermod -aG docker username\nnewgrp docker #更新docker用户组', 'bodyHTML': '

今天终于在阿里云入手了一台 2核(vCPU)+ 2GiB + 3Mbps 的 ECS,安装了最新的 Rocky Linux release 9.3 (Blue Onyx),记录一下开箱后的一些基础配置。

\n\n

aliyun-99-plan

\n

Hostname

\n
[root@r0sasd1bQi ~]# hostnamectl   # 查看一下当前主机名的情况\n[root@r0sasd1bQi ~]# hostnamectl set-hostname shen-server --static\n[root@r0sasd1bQi ~]# hostnamectl status\n[root@r0sasd1bQi ~]# reboot now    # 重启服务器\n
\n

创建新用户

\n

使用 adduser 命令将新用户添加到系统中:

\n
adduser shenweiyan    # 创建新用户\npasswd shenweiyan     # 修改密码
\n

用户添加超级权限

\n

shenweiyan 用户添加超级权限(/etc/sudoers):

\n
shenweiyan      ALL=(ALL)       NOPASSWD: ALL\n
\n

自定义快捷方式

\n

~/.bashrc 最后新增一下用户自定义的快捷方式。

\n
# User Specific Alias\nalias disp=\'display\'\nalias rm=\'rm -i\'\nalias la=\'ls -al\'\nalias ll=\'ls -lh\'\nalias le=\'less -S\'\n\n# Custom History setting\n# HISTFILESIZE 定义了在 .bash_history 中保存命令的记录总数\nHISTFILESIZE=3000000\n# HISTSIZE 定义了 history 命令输出的记录数\nHISTSIZE=3000\n# 定义 History 输出格式\nexport HISTTIMEFORMAT=\'%F %T \'\n# 使用 HISTCONTROL 从命令历史中剔除连续重复的条目\nHISTCONTROL=ignoredups\n# 将 bash 内存中历史命令追加到 .bash_history 历史命令文件中, 默认只有退出 shell 是才会保存\nPROMPT_COMMAND="history -a"\n\n# Login Style\nPS1=\'\\033[35;1m\\u@\\h \\[\\e[m\\]\\t \\[\\033[36;1m\\]$(pwd) \\n$ \\[\\e[m\\]\'\nclear;\n
\n

epel-release

\n
\n

企业版 Linux 附加软件包(Extra Packages for Enterprise Linux,以下简称 EPEL)是一个 Fedora 特别兴趣小组,用以创建、维护以及管理针对企业版 Linux 的一个高质量附加软件包集,面向的对象包括但不限于 红帽企业版 Linux (RHEL)、 CentOS、Scientific Linux (SL)、Oracle Linux (OL) 。

\n

参考:EPEL/zh-cn - Fedora Project Wiki

\n
\n
# 下面两个命令都可以安装\nsudo dnf install epel-release\nsudo dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
\n

Htop 和 Btop

\n

Htop 是一个基于 C 编写的跨平台的交互式流程查看器,htoptop 的一个增强替代品,提供了更加友好的用户界面和更多的功能,相比系统自带的 top 更加直观好用。

\n
sudo dnf install htop
\n

btop 也是一个改进版的 Linux top 命令,这个命令不仅列出了各种系统使用情况,包括内存、磁盘、网络和进程,而且还允许与鼠标互动。即使是在服务器安装上,你也可以在 btop 上指指点点,以树形方式查看进程,隐藏或显示某些显示,并访问选项菜单,在那里你可以调整显示的外观和感觉。

\n
sudo dnf install btop
\n

Docker 安装与使用

\n

主要参考《How To Install and Use Docker on Rocky Linux 9》,具体步骤如下:

\n
    \n
  • \n

    add the official Docker repository

    \n
    sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
    \n
  • \n
  • \n

    install Docker

    \n
    sudo dnf install docker-ce docker-ce-cli containerd.io
    \n
  • \n
  • \n

    start the Docker daemon

    \n
    sudo systemctl start docker
    \n
  • \n
  • \n

    Verify that it’s running

    \n
    sudo systemctl status docker
    \n
    Output\n● docker.service - Docker Application Container Engine\n   Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)\n   Active: active (running) since Sun 2016-05-01 06:53:52 CDT; 1 weeks 3 days ago\n     Docs: https://docs.docker.com\n Main PID: 749 (docker)\n
    \n
  • \n
  • \n

    make sure it starts at every server reboot

    \n
    sudo systemctl enable docker
    \n
  • \n
  • \n

    配置非 root 用户使用 Docker

    \n
    sudo usermod -aG docker username\nnewgrp docker                     #更新docker用户组
    \n
  • \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '1.3.17-服务器配置使用'}]}, 'comments': {'nodes': []}}, {'title': '我的随笔和博客', 'number': 59, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/59', 'createdAt': '2024-03-04T01:27:09Z', 'lastEditedAt': None, 'updatedAt': '2024-03-04T01:27:10Z', 'body': '我的站点中把[随笔](https://weiyan.cc/note/)和[博客](https://weiyan.cc/blog/)分成了两个平行的导航,其实内容是一样的,只是原文托管的平台不一样而已。\r\n\r\n\r\n\r\n[随笔](https://weiyan.cc/note/) 的内容最开始是在语雀的[随笔与乱弹](https://www.yuque.com/shenweiyan/notebook)写的,导出来后加到现在的站点中,独立成了现在看到的[随笔](https://weiyan.cc/note/)。[博客](https://weiyan.cc/blog/) 则是从 2023 年起写在 [Knowledge-Garden](https://github.com/shenweiyan/Knowledge-Garden) 的 [discussions](https://github.com/shenweiyan/Knowledge-Garden/discussions/) 上的一些非技术相关杂文。', 'bodyText': '我的站点中把随笔和博客分成了两个平行的导航,其实内容是一样的,只是原文托管的平台不一样而已。\n\n随笔 的内容最开始是在语雀的随笔与乱弹写的,导出来后加到现在的站点中,独立成了现在看到的随笔。博客 则是从 2023 年起写在 Knowledge-Garden 的 discussions 上的一些非技术相关杂文。', 'bodyHTML': '

我的站点中把随笔博客分成了两个平行的导航,其实内容是一样的,只是原文托管的平台不一样而已。

\n\n

随笔 的内容最开始是在语雀的随笔与乱弹写的,导出来后加到现在的站点中,独立成了现在看到的随笔博客 则是从 2023 年起写在 Knowledge-Gardendiscussions 上的一些非技术相关杂文。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '如今迈步从头越', 'number': 58, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/58', 'createdAt': '2024-02-20T03:57:52Z', 'lastEditedAt': '2024-08-06T07:13:06Z', 'updatedAt': '2024-08-06T07:13:06Z', 'body': "2024 年应该是不太平凡的一年,农历新年后经历了很多的事情,生活也好工作也好,都不太平静。\r\n\r\n\r\n\r\n尤其对于工作而言,有一些更加深入的体会,明白很多人和事都并非表面那么简单。职场多年一路走来,曾经的迷茫不解,焦虑,纠结,吐槽,走到最后不由得越来越小心翼翼、如履薄冰。时间实际上是人的积极存在,它不仅是人的生命的尺度,而且是人的发展的空间。总的来说,更加要学会保护好自己,做事情多留点心,多一些思考。 \r\n美丽的林间公路风景\r\n\r\n人家说,能力也大,责任越大。对于个人职业和工作,更多的是权限越大,责任越大,任何的权限并非是越大越好。", 'bodyText': '2024 年应该是不太平凡的一年,农历新年后经历了很多的事情,生活也好工作也好,都不太平静。\n\n尤其对于工作而言,有一些更加深入的体会,明白很多人和事都并非表面那么简单。职场多年一路走来,曾经的迷茫不解,焦虑,纠结,吐槽,走到最后不由得越来越小心翼翼、如履薄冰。时间实际上是人的积极存在,它不仅是人的生命的尺度,而且是人的发展的空间。总的来说,更加要学会保护好自己,做事情多留点心,多一些思考。\n\n人家说,能力也大,责任越大。对于个人职业和工作,更多的是权限越大,责任越大,任何的权限并非是越大越好。', 'bodyHTML': '

2024 年应该是不太平凡的一年,农历新年后经历了很多的事情,生活也好工作也好,都不太平静。

\n\n

尤其对于工作而言,有一些更加深入的体会,明白很多人和事都并非表面那么简单。职场多年一路走来,曾经的迷茫不解,焦虑,纠结,吐槽,走到最后不由得越来越小心翼翼、如履薄冰。时间实际上是人的积极存在,它不仅是人的生命的尺度,而且是人的发展的空间。总的来说,更加要学会保护好自己,做事情多留点心,多一些思考。
\n美丽的林间公路风景

\n

人家说,能力也大,责任越大。对于个人职业和工作,更多的是权限越大,责任越大,任何的权限并非是越大越好。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '使用 Planemo 进行 Galaxy 工具开发', 'number': 57, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/57', 'createdAt': '2024-02-04T08:26:38Z', 'lastEditedAt': None, 'updatedAt': '2024-04-24T06:29:34Z', 'body': '> 说明:本文章原文发布于 《[使用 Planemo 进行 Galaxy 工具开发 - 语雀](https://www.yuque.com/shenweiyan/biox/planemo-for-galaxy)》,部分内容已更新。\r\n\r\n文章开始前,我们先了解一下 Planemo 到底是个什么东西。\r\n\r\n> Command-line utilities to assist in developing [Galaxy](http://galaxyproject.org/) and [Common Workflow Language](https://www.commonwl.org/) artifacts - including tools, workflows, and training materials.\r\n\r\n说白了,Planemo 就是用于 Galaxy 平台工具和 WDL 通用工作流语言相关产品辅助开发的一个命令行工具,这个程序集可以用于工具、流程,以及培训教材的开发。\r\n\r\n\r\n\r\n## 安装 Planemo \r\n\r\n无论是 pip 还是 conda 都可以安装 Planemo:\r\n```bash\r\n$ pip install planemo\r\n$ pip install -U git+git://github.com/galaxyproject/planemo.git\r\n```\r\n```bash\r\n$ conda config --add channels bioconda\r\n$ conda config --add channels conda-forge\r\n$ conda install planemo\r\n```\r\n\r\n接下来,进入今天的正题,我们来详细介绍一下怎么使用 Planemo 进行 Galaxy 工具开发。\r\n\r\n## 基础用法\r\n\r\n本指南将演示如何使用 Heng Li 的 `Seqtk` 软件包构建命令工具,该软件包用于处理 FASTA 和 FASTQ 文件中的序列数据。\r\n\r\n首先,我们需要先安装 `Seqtk` 。在这里,我们使用 `conda` 来安装 `Seqtk` (你也可以使用其他的方法安装)。\r\n```bash\r\n$ conda install --force --yes -c conda-forge -c bioconda seqtk=1.2\r\n ... seqtk installation ...\r\n$ seqtk seq\r\n Usage: seqtk seq [options] |\r\n Options: -q INT mask bases with quality lower than INT [0]\r\n -X INT mask bases with quality higher than INT [255]\r\n -n CHAR masked bases converted to CHAR; 0 for lowercase [0]\r\n -l INT number of residues per line; 0 for 2^32-1 [0]\r\n -Q INT quality shift: ASCII-INT gives base quality [33]\r\n -s INT random seed (effective with -f) [11]\r\n -f FLOAT sample FLOAT fraction of sequences [1]\r\n -M FILE mask regions in BED or name list FILE [null]\r\n -L INT drop sequences with length shorter than INT [0]\r\n -c mask complement region (effective with -M)\r\n -r reverse complement\r\n -A force FASTA output (discard quality)\r\n -C drop comments at the header lines\r\n -N drop sequences containing ambiguous bases\r\n -1 output the 2n-1 reads only\r\n -2 output the 2n reads only\r\n -V shift quality by \'(-Q) - 33\'\r\n```\r\n接下来,我们将下载一个 FASTQ 示例文件,并测试一个简单的 Seqtk 命令 `seq` ,该命令将 FASTQ 文件转换为 FASTA。\r\n```bash\r\n$ wget https://raw.githubusercontent.com/galaxyproject/galaxy-test-data/master/2.fastq\r\n$ seqtk seq -A 2.fastq > 2.fasta\r\n$ cat 2.fasta\r\n>EAS54_6_R1_2_1_413_324\r\nCCCTTCTTGTCTTCAGCGTTTCTCC\r\n>EAS54_6_R1_2_1_540_792\r\nTTGGCAGGCCAAGGCCGATGGATCA\r\n>EAS54_6_R1_2_1_443_348\r\nGTTGCTTCTGGCGTGGGTGGGGGGG\r\n```\r\n有关功能齐全的 Seqtk 包封装,可以在 GitHub 上查看 [Helena Rasche\'s wrappers](https://github.com/galaxyproject/tools-iuc/tree/master/tools/seqtk)。\r\n\r\nGalaxy 工具文件只是 XML 文件,因此此时可以打开文本编辑器并开始编写工具。Planemo 有一个命令 `tool_init` 可以快速生成一些样板 XML,因此首先开始。\r\n```bash\r\n$ planemo tool_init --id \'seqtk_seq\' --name \'Convert to FASTA (seqtk)\'\r\n```\r\n`tool_init` 命令可以采用各种复杂的参数,但如上面展示的 `--id` 和 `--name` 是其中两个最基本的参数。每个 Galaxy 工具都需要一个 ID(这是 Galaxy 自身用来标识该工具的简短标识符)和一个名称(此名称会显示给 Galaxy 用户,并且应该是该工具的简短描述)。工具名称可以包含空格,但其 ID 不能包含空格。\r\n\r\n上面的命令将生成一个 seqtk_seq.xml 文件,这个文件看起来像这样:\r\n```xml\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n\r\n```\r\n这个生成的模板 XML 文件具有了 Galaxy 工具所需的公共部分内容,但你仍然需要打开编辑器并填写命令模板、输入参数描述、工具输出信息、帮助部分信息等。\r\n\r\n`tool_init` 命令也可以做得更好。 们可以使用在 `seqtk seq -a 2.fastq> 2.fasta` 上面尝试过的测试命令作为示例,通过指定输入和输出来生成命令块,如下所示。\r\n```bash\r\n$ planemo tool_init --force \\\r\n --id \'seqtk_seq\' \\\r\n --name \'Convert to FASTA (seqtk)\' \\\r\n --requirement seqtk@1.2 \\\r\n --example_command \'seqtk seq -a 2.fastq > 2.fasta\' \\\r\n --example_input 2.fastq \\\r\n --example_output 2.fasta\r\n```\r\n这将生成以下 XML 文件- 该文件具有正确的输入和输出定义以及实际的命令模板。\r\n```xml\r\n\r\n \r\n seqtk\r\n \r\n \'$output1\'\r\n ]]>\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n(\r\n```\r\n如本节开头所示,命令 `seqtk seq` 会为 `seq` 命令生成帮助消息。 `tool_init` 可以获取该帮助消息,并使用 `help_from_command` 选项将其正确粘贴在生成的工具 XML 文件中。\r\n\r\n通常,命令帮助消息并不完全适用于工具,因为它们会提到参数名称和由工具抽象出来的类似细节,但它们可能是一个很好的起点。\r\n\r\n以下 Planemo 的 `tool_init` 的调用已增强为使用 `--help_from_command`。\r\n```bash\r\n$ planemo tool_init --force \\\r\n --id \'seqtk_seq\' \\\r\n --name \'Convert to FASTA (seqtk)\' \\\r\n --requirement seqtk@1.2 \\\r\n --example_command \'seqtk seq -a 2.fastq > 2.fasta\' \\\r\n --example_input 2.fastq \\\r\n --example_output 2.fasta \\\r\n --test_case \\\r\n --cite_url \'https://github.com/lh3/seqtk\' \\\r\n --help_from_command \'seqtk seq\'\r\n```\r\n\r\n除了演示 `--help_from_command` 之外,这还演示了使用 `--test_case` 从我们的示例生成测试用例并为基础工具添加引用。生成的工具 XML 文件为:\r\n```xml\r\n\r\n \r\n seqtk\r\n \r\n \'$output1\'\r\n ]]>\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n |\r\n\r\nOptions: -q INT mask bases with quality lower than INT [0]\r\n -X INT mask bases with quality higher than INT [255]\r\n -n CHAR masked bases converted to CHAR; 0 for lowercase [0]\r\n -l INT number of residues per line; 0 for 2^32-1 [0]\r\n -Q INT quality shift: ASCII-INT gives base quality [33]\r\n -s INT random seed (effective with -f) [11]\r\n -f FLOAT sample FLOAT fraction of sequences [1]\r\n -M FILE mask regions in BED or name list FILE [null]\r\n -L INT drop sequences with length shorter than INT [0]\r\n -c mask complement region (effective with -M)\r\n -r reverse complement\r\n -A force FASTA output (discard quality)\r\n -C drop comments at the header lines\r\n -N drop sequences containing ambiguous bases\r\n -1 output the 2n-1 reads only\r\n -2 output the 2n reads only\r\n -V shift quality by \'(-Q) - 33\'\r\n -U convert all bases to uppercases\r\n -S strip of white spaces in sequences\r\n\r\n\r\n ]]>\r\n \r\n \r\n@misc{githubseqtk,\r\n author = {LastTODO, FirstTODO},\r\n year = {TODO},\r\n title = {seqtk},\r\n publisher = {GitHub},\r\n journal = {GitHub repository},\r\n url = {https://github.com/lh3/seqtk},\r\n}\r\n \r\n\r\n```\r\n\r\n至此,我们有了一个功能相当齐全的 Galaxy 工具,它带有测试和帮助。这是一个非常简单的示例——通常,您需要在工具中投入更多工作才能实现这一点, `tool_init` 实际上只是为了让您入门而设计的。\r\n\r\n现在让我们检查并测试我们开发的工具。Planemo的 `lint`(或仅 `l` )命令将检查工具的 XML 有效性,检查是否有明显的错误以及是否符合 IUC 的最佳做法。\r\n```bash\r\n$ planemo l\r\nLinting tool /opt/galaxy/tools/seqtk_seq.xml\r\nApplying linter tests... CHECK\r\n.. CHECK: 1 test(s) found.\r\nApplying linter output... CHECK\r\n.. INFO: 1 outputs found.\r\nApplying linter inputs... CHECK\r\n.. INFO: Found 1 input parameters.\r\nApplying linter help... CHECK\r\n.. CHECK: Tool contains help section.\r\n.. CHECK: Help contains valid reStructuredText.\r\nApplying linter general... CHECK\r\n.. CHECK: Tool defines a version [0.1.0].\r\n.. CHECK: Tool defines a name [Convert to FASTA (seqtk)].\r\n.. CHECK: Tool defines an id [seqtk_seq].\r\n.. CHECK: Tool targets 16.01 Galaxy profile.\r\nApplying linter command... CHECK\r\n.. INFO: Tool contains a command.\r\nApplying linter citations... CHECK\r\n.. CHECK: Found 1 likely valid citations.\r\nApplying linter tool_xsd... CHECK\r\n.. INFO: File validates against XML schema.\r\n```\r\n默认情况下, `lint` 会在您当前的工作目录中找到所有工具,但是我们可以使用 `planemo lint seqtk_seq.xml` 指定一个特定的工具。\r\n\r\n接下来,我们可以使用 `test`(或仅执行 `t` )命令运行工具的功能测试。这将打印很多输出(因为它启动了 Galaxy 实例),但最终应该显示我们通过的一项测试。\r\n\r\n> 如果你的服务器已经安装了 Galaxy 实例,你可以编辑 ~/.planemo.yml 文件,指定 Galaxy 实例路径。\r\n\r\n```yaml\r\n## Specify a default galaxy_root for the `test` and `serve` commands here.\r\ngalaxy_root: /home/user/galaxy\r\n```\r\n> 完整的 `~/.planemo.yml` 示例,参考:[https://planemo.readthedocs.io/en/latest/configuration.html](https://planemo.readthedocs.io/en/latest/configuration.html)\r\n\r\n```bash\r\n$ planemo t\r\n...\r\nAll 1 test(s) executed passed.\r\nseqtk_seq[0]: passed\r\n```\r\n除了在控制台中将测试结果显示为红色(失败)或绿色(通过)外,Planemo 还默认为测试结果创建 HTML 报告。 还有更多测试报告选项可用,例如 `--test_output_xunit`,在某些持续集成环境中很有用。有关更多选项,请参见 `planemo test --help` ,以及 `test_reports` 命令。\r\n\r\n现在,我们可以使用 `serve`(或仅使用 `s` )命令打开 Galaxy。\r\n```bash\r\n$ planemo s\r\n...\r\nserving on http://127.0.0.1:9090\r\n```\r\n\r\n在网络浏览器中打开 [http://127.0.0.1:9090](http://127.0.0.1:9090) 以查看您的新工具。\r\n\r\n服务和测试可以通过各种命令行参数传递,例如 `--galaxy_root`,以指定要使用的 Galaxy 实例(默认情况下,planemo 将仅为 planemo 下载和管理实例)。\r\n\r\n## 简单参数\r\n\r\n我们为 `seqtk seq` 命令构建了一个工具包的封装,但是该工具实际上具有我们可能希望向 Galaxy 用户公开的其他选项。\r\n\r\n让我们从 `help` 命令中获取一些参数,并构建 Galaxy 的 `param` 块以粘贴到该工具的 `input` 块中。\r\n```bash\r\n-V shift quality by \'(-Q) - 33\'\r\n```\r\n\r\n在上一节中,我们看到了输入文件在 `param` 块中是一个 `data` 的类型,除此之外我们还可以使用许多不同种类的参数。如标志参数(例如以上 `-V` 参数),通常在 Galaxy 工具的 XML 文件中由 `boolean` 来表示。\r\n```xml\r\n\r\n```\r\n然后,我们可以将 `$shift_quality` 粘贴在 `command` 块中,如果用户选择了此选项,它将扩展为 `-V` (因为我们已将其定义为 `truevalue` )。如果用户未选择此选项,则 `$shift_quality` 将仅扩展为空字符串,而不会影响生成的命令行。\r\n\r\n现在考虑以下的 `seqtk seq` 参数:\r\n```bash\r\n-q INT mask bases with quality lower than INT [0]\r\n-X INT mask bases with quality higher than INT [255]\r\n```\r\n\r\n这些可以转换为 Galaxy 参数,如下所示:\r\n```xml\r\n\r\n\r\n```\r\n\r\n这些可以作为 `-q $quality_min -X $quality_max` 添加到命令标签中。\r\n\r\n此时,该工具将如下所示:\r\n```xml\r\n\r\n \r\n seqtk\r\n \r\n \'$output1\'\r\n ]]>\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n |\r\n\r\nOptions: -q INT mask bases with quality lower than INT [0]\r\n -X INT mask bases with quality higher than INT [255]\r\n -n CHAR masked bases converted to CHAR; 0 for lowercase [0]\r\n -l INT number of residues per line; 0 for 2^32-1 [0]\r\n -Q INT quality shift: ASCII-INT gives base quality [33]\r\n -s INT random seed (effective with -f) [11]\r\n -f FLOAT sample FLOAT fraction of sequences [1]\r\n -M FILE mask regions in BED or name list FILE [null]\r\n -L INT drop sequences with length shorter than INT [0]\r\n -c mask complement region (effective with -M)\r\n -r reverse complement\r\n -A force FASTA output (discard quality)\r\n -C drop comments at the header lines\r\n -N drop sequences containing ambiguous bases\r\n -1 output the 2n-1 reads only\r\n -2 output the 2n reads only\r\n -V shift quality by \'(-Q) - 33\'\r\n -U convert all bases to uppercases\r\n\r\n\r\n ]]>\r\n \r\n \r\n@misc{githubseqtk,\r\n author = {LastTODO, FirstTODO},\r\n year = {TODO},\r\n title = {seqtk},\r\n publisher = {GitHub},\r\n journal = {GitHub repository},\r\n url = {https://github.com/lh3/seqtk},\r\n}\r\n \r\n\r\n```\r\n\r\n## 条件参数\r\n\r\n以前的参数很简单,因为它们总是出现,现在考虑一下下面的参数。\r\n```bash\r\n-M FILE mask regions in BED or name list FILE [null]\r\n```\r\n\r\n我们可以通过添加属性 `optional ="true"` 将该数据类型参数标记为可选。\r\n```xml\r\n\r\n```\r\n\r\n然后,不仅可以直接在命令块中使用 `$mask_regions`,还可以将其包装在 `if` 语句中(因为工具 XML 文件支持 [Cheetah](https://cheetahtemplate.org/users_guide/index.html))。\r\n```xml\r\n#if $mask_regions\r\n-M \'$mask_regions\'\r\n#end if\r\n```\r\n\r\n\r\n接着,我们考虑这一组参数:\r\n```bash\r\n-s INT random seed (effective with -f) [11]\r\n-f FLOAT sample FLOAT fraction of sequences [1]\r\n```\r\n\r\n在这种情况下,只有在设置了样本参数的情况下,才能看到或使用 `-s` 随机种子参数。我们可以使用 `conditional` 条件块来表达这一点。\r\n```xml\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n\r\n```\r\n\r\n在命令块中,我们可以再次使用 `if` 语句包括这些参数。\r\n```xml\r\n#if $sample.sample_selector\r\n-f $sample.fraction -s $sample.seed\r\n#end if\r\n```\r\n\r\n注意,我们必须使用 `sample.` 的前缀来引用这个参数,因为它们是在 `sample` 的条件块内定义的。\r\n\r\n现在该工具的最新版本如下:\r\n```xml\r\n\r\n \r\n seqtk\r\n \r\n \'$output1\'\r\n ]]>\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n |\r\n\r\nOptions: -q INT mask bases with quality lower than INT [0]\r\n -X INT mask bases with quality higher than INT [255]\r\n -n CHAR masked bases converted to CHAR; 0 for lowercase [0]\r\n -l INT number of residues per line; 0 for 2^32-1 [0]\r\n -Q INT quality shift: ASCII-INT gives base quality [33]\r\n -s INT random seed (effective with -f) [11]\r\n -f FLOAT sample FLOAT fraction of sequences [1]\r\n -M FILE mask regions in BED or name list FILE [null]\r\n -L INT drop sequences with length shorter than INT [0]\r\n -c mask complement region (effective with -M)\r\n -r reverse complement\r\n -A force FASTA output (discard quality)\r\n -C drop comments at the header lines\r\n -N drop sequences containing ambiguous bases\r\n -1 output the 2n-1 reads only\r\n -2 output the 2n reads only\r\n -V shift quality by \'(-Q) - 33\'\r\n -U convert all bases to uppercases\r\n\r\n\r\n ]]>\r\n \r\n \r\n@misc{githubseqtk,\r\n author = {LastTODO, FirstTODO},\r\n year = {TODO},\r\n title = {seqtk},\r\n publisher = {GitHub},\r\n journal = {GitHub repository},\r\n url = {https://github.com/lh3/seqtk},\r\n}\r\n \r\n\r\n```\r\n对于这样的工具,这些工具有很多选项,但在大多数情况下使用默认值是首选——一个常见的习惯用法是使用条件将参数分为简单部分和高级部分。\r\n\r\n使用惯用法,更新此工具后的 XML 如下所示:\r\n```xml\r\n\r\n \r\n seqtk\r\n \r\n \'$output1\'\r\n ]]>\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n |\r\n\r\nOptions: -q INT mask bases with quality lower than INT [0]\r\n -X INT mask bases with quality higher than INT [255]\r\n -n CHAR masked bases converted to CHAR; 0 for lowercase [0]\r\n -l INT number of residues per line; 0 for 2^32-1 [0]\r\n -Q INT quality shift: ASCII-INT gives base quality [33]\r\n -s INT random seed (effective with -f) [11]\r\n -f FLOAT sample FLOAT fraction of sequences [1]\r\n -M FILE mask regions in BED or name list FILE [null]\r\n -L INT drop sequences with length shorter than INT [0]\r\n -c mask complement region (effective with -M)\r\n -r reverse complement\r\n -A force FASTA output (discard quality)\r\n -C drop comments at the header lines\r\n -N drop sequences containing ambiguous bases\r\n -1 output the 2n-1 reads only\r\n -2 output the 2n reads only\r\n -V shift quality by \'(-Q) - 33\'\r\n -U convert all bases to uppercases\r\n\r\n\r\n ]]>\r\n \r\n \r\n@misc{githubseqtk,\r\n author = {LastTODO, FirstTODO},\r\n year = {TODO},\r\n title = {seqtk},\r\n publisher = {GitHub},\r\n journal = {GitHub repository},\r\n url = {https://github.com/lh3/seqtk},\r\n}\r\n \r\n\r\n```\r\n\r\n## 脚本封装\r\n\r\nTool Shed 上已经提供了许多常见的生物信息学应用程序,因此一项常见的开发任务是将各种复杂程度的脚本集成到 Galaxy 中。\r\n\r\n考虑以下小型 Perl 脚本。\r\n```perl\r\n#!/usr/bin/perl -w\r\n\r\n# usage : perl toolExample.pl \r\n\r\nopen (IN, "<$ARGV[0]");\r\nopen (OUT, ">$ARGV[1]");\r\nwhile () {\r\n chop;\r\n if (m/^>/) {\r\n s/^>//;\r\n if ($. > 1) {\r\n print OUT sprintf("%.3f", $gc/$length) . "\\n";\r\n }\r\n $gc = 0;\r\n $length = 0;\r\n } else {\r\n ++$gc while m/[gc]/ig;\r\n $length += length $_;\r\n }\r\n}\r\nprint OUT sprintf("%.3f", $gc/$length) . "\\n";\r\nclose( IN );\r\nclose( OUT );\r\n```\r\n\r\n可以按照以下步骤为此脚本构建 Galaxy 工具,并将脚本与工具 XML 文件本身放在同一目录中。这里的特殊值 `$__ tool_directory__` 是指工具(即 xml 文件)所在的目录。\r\n```xml\r\n\r\n for each sequence in a file\r\n perl \'$__tool_directory__/gc_content.pl\' \'$input\' output.tsv\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\nThis tool computes GC content from a FASTA file.\r\n \r\n\r\n```\r\n\r\n## Macros 宏集\r\n\r\n如果您希望为单个相对简单的应用程序或脚本编写工具,则应跳过本节。如果您希望维护一系列相关工具——经验表明,您将意识到有很多重复的 XML 可以很好地做到这一点。Galaxy工具 XML 宏可以帮助减少这种重复。\r\n\r\n通过使用 `--macros` 标志,Planemo 的 `tool_init` 命令可用于生成适合工具套件的宏文件。我们看一下以前的 `tool_init` 命令的变体(唯一的区别是现在我们添加了 `--macros` 标志)。\r\n```bash\r\n$ planemo tool_init --force \\\r\n --macros \\\r\n --id \'seqtk_seq\' \\\r\n --name \'Convert to FASTA (seqtk)\' \\\r\n --requirement seqtk@1.2 \\\r\n --example_command \'seqtk seq -A 2.fastq > 2.fasta\' \\\r\n --example_input 2.fastq \\\r\n --example_output 2.fasta \\\r\n --test_case \\\r\n --help_from_command \'seqtk seq\'\r\n```\r\n这将在当前目录中产生两个文件( `seqtk_seq.xml` 和 `macros.xml`),而不是一个。\r\n```xml\r\n\r\n \r\n macros.xml\r\n \r\n \r\n \'$output1\'\r\n ]]>\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n |\r\n\r\nOptions: -q INT mask bases with quality lower than INT [0]\r\n -X INT mask bases with quality higher than INT [255]\r\n -n CHAR masked bases converted to CHAR; 0 for lowercase [0]\r\n -l INT number of residues per line; 0 for 2^32-1 [0]\r\n -Q INT quality shift: ASCII-INT gives base quality [33]\r\n -s INT random seed (effective with -f) [11]\r\n -f FLOAT sample FLOAT fraction of sequences [1]\r\n -M FILE mask regions in BED or name list FILE [null]\r\n -L INT drop sequences with length shorter than INT [0]\r\n -c mask complement region (effective with -M)\r\n -r reverse complement\r\n -A force FASTA output (discard quality)\r\n -C drop comments at the header lines\r\n -N drop sequences containing ambiguous bases\r\n -1 output the 2n-1 reads only\r\n -2 output the 2n reads only\r\n -V shift quality by \'(-Q) - 33\'\r\n -U convert all bases to uppercases\r\n -S strip of white spaces in sequences\r\n\r\n\r\n ]]>\r\n \r\n\r\n```\r\n```xml\r\n\r\n \r\n \r\n seqtk\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n\r\n```\r\n\r\n如您在上面的代码中所看到的,宏是可重用的 XML 块,它们使避免重复和保持 XML 简洁变得更加容易。\r\n\r\n\r\n## 参考资料\r\n\r\n- [Macros syntax](https://wiki.galaxyproject.org/Admin/Tools/ToolConfigSyntax#Reusing_Repeated_Configuration_Elements) on the Galaxy Wiki.\r\n- [GATK tools](https://github.com/galaxyproject/tools-iuc/tree/master/tools/gatk2) (example tools making extensive use of macros)\r\n- [gemini tools](https://github.com/galaxyproject/tools-iuc/tree/master/tools/gemini) (example tools making extensive use of macros)\r\n- [bedtools tools](https://github.com/galaxyproject/tools-iuc/tree/master/tools/bedtools) (example tools making extensive use of macros)\r\n- Macros implementation details - [Pull Request #129](https://bitbucket.org/galaxy/galaxy-central/pull-request/129/implement-macro-engine-to-reduce-tool/diff) and [Pull Request #140](https://bitbucket.org/galaxy/galaxy-central/pull-request/140/improvements-to-tool-xml-macroing-system/diff)\r\n- [Galaxy’s Tool XML Syntax](https://docs.galaxyproject.org/en/latest/dev/schema.html)\r\n- [Big List of Tool Development Resources](https://galaxyproject.org/develop/resources-tools/)\r\n- [Cheetah templating](https://cheetahtemplate.org/users_guide/index.html)', 'bodyText': '说明:本文章原文发布于 《使用 Planemo 进行 Galaxy 工具开发 - 语雀》,部分内容已更新。\n\n文章开始前,我们先了解一下 Planemo 到底是个什么东西。\n\nCommand-line utilities to assist in developing Galaxy and Common Workflow Language artifacts - including tools, workflows, and training materials.\n\n说白了,Planemo 就是用于 Galaxy 平台工具和 WDL 通用工作流语言相关产品辅助开发的一个命令行工具,这个程序集可以用于工具、流程,以及培训教材的开发。\n\n安装 Planemo\n无论是 pip 还是 conda 都可以安装 Planemo:\n$ pip install planemo\n$ pip install -U git+git://github.com/galaxyproject/planemo.git\n$ conda config --add channels bioconda\n$ conda config --add channels conda-forge\n$ conda install planemo\n接下来,进入今天的正题,我们来详细介绍一下怎么使用 Planemo 进行 Galaxy 工具开发。\n基础用法\n本指南将演示如何使用 Heng Li 的 Seqtk 软件包构建命令工具,该软件包用于处理 FASTA 和 FASTQ 文件中的序列数据。\n首先,我们需要先安装 Seqtk 。在这里,我们使用 conda 来安装 Seqtk (你也可以使用其他的方法安装)。\n$ conda install --force --yes -c conda-forge -c bioconda seqtk=1.2\n ... seqtk installation ...\n$ seqtk seq\n Usage: seqtk seq [options] |\n Options: -q INT mask bases with quality lower than INT [0]\n -X INT mask bases with quality higher than INT [255]\n -n CHAR masked bases converted to CHAR; 0 for lowercase [0]\n -l INT number of residues per line; 0 for 2^32-1 [0]\n -Q INT quality shift: ASCII-INT gives base quality [33]\n -s INT random seed (effective with -f) [11]\n -f FLOAT sample FLOAT fraction of sequences [1]\n -M FILE mask regions in BED or name list FILE [null]\n -L INT drop sequences with length shorter than INT [0]\n -c mask complement region (effective with -M)\n -r reverse complement\n -A force FASTA output (discard quality)\n -C drop comments at the header lines\n -N drop sequences containing ambiguous bases\n -1 output the 2n-1 reads only\n -2 output the 2n reads only\n -V shift quality by \'(-Q) - 33\'\n接下来,我们将下载一个 FASTQ 示例文件,并测试一个简单的 Seqtk 命令 seq ,该命令将 FASTQ 文件转换为 FASTA。\n$ wget https://raw.githubusercontent.com/galaxyproject/galaxy-test-data/master/2.fastq\n$ seqtk seq -A 2.fastq > 2.fasta\n$ cat 2.fasta\n>EAS54_6_R1_2_1_413_324\nCCCTTCTTGTCTTCAGCGTTTCTCC\n>EAS54_6_R1_2_1_540_792\nTTGGCAGGCCAAGGCCGATGGATCA\n>EAS54_6_R1_2_1_443_348\nGTTGCTTCTGGCGTGGGTGGGGGGG\n有关功能齐全的 Seqtk 包封装,可以在 GitHub 上查看 Helena Rasche\'s wrappers。\nGalaxy 工具文件只是 XML 文件,因此此时可以打开文本编辑器并开始编写工具。Planemo 有一个命令 tool_init 可以快速生成一些样板 XML,因此首先开始。\n$ planemo tool_init --id \'seqtk_seq\' --name \'Convert to FASTA (seqtk)\'\ntool_init 命令可以采用各种复杂的参数,但如上面展示的 --id 和 --name 是其中两个最基本的参数。每个 Galaxy 工具都需要一个 ID(这是 Galaxy 自身用来标识该工具的简短标识符)和一个名称(此名称会显示给 Galaxy 用户,并且应该是该工具的简短描述)。工具名称可以包含空格,但其 ID 不能包含空格。\n上面的命令将生成一个 seqtk_seq.xml 文件,这个文件看起来像这样:\n\n \n \n \n \n \n \n \n \n\n这个生成的模板 XML 文件具有了 Galaxy 工具所需的公共部分内容,但你仍然需要打开编辑器并填写命令模板、输入参数描述、工具输出信息、帮助部分信息等。\ntool_init 命令也可以做得更好。 们可以使用在 seqtk seq -a 2.fastq> 2.fasta 上面尝试过的测试命令作为示例,通过指定输入和输出来生成命令块,如下所示。\n$ planemo tool_init --force \\\n --id \'seqtk_seq\' \\\n --name \'Convert to FASTA (seqtk)\' \\\n --requirement seqtk@1.2 \\\n --example_command \'seqtk seq -a 2.fastq > 2.fasta\' \\\n --example_input 2.fastq \\\n --example_output 2.fasta\n这将生成以下 XML 文件- 该文件具有正确的输入和输出定义以及实际的命令模板。\n\n \n seqtk\n \n \'$output1\'\n ]]>\n \n \n \n \n \n \n \n(\n如本节开头所示,命令 seqtk seq 会为 seq 命令生成帮助消息。 tool_init 可以获取该帮助消息,并使用 help_from_command 选项将其正确粘贴在生成的工具 XML 文件中。\n通常,命令帮助消息并不完全适用于工具,因为它们会提到参数名称和由工具抽象出来的类似细节,但它们可能是一个很好的起点。\n以下 Planemo 的 tool_init 的调用已增强为使用 --help_from_command。\n$ planemo tool_init --force \\\n --id \'seqtk_seq\' \\\n --name \'Convert to FASTA (seqtk)\' \\\n --requirement seqtk@1.2 \\\n --example_command \'seqtk seq -a 2.fastq > 2.fasta\' \\\n --example_input 2.fastq \\\n --example_output 2.fasta \\\n --test_case \\\n --cite_url \'https://github.com/lh3/seqtk\' \\\n --help_from_command \'seqtk seq\'\n除了演示 --help_from_command 之外,这还演示了使用 --test_case 从我们的示例生成测试用例并为基础工具添加引用。生成的工具 XML 文件为:\n\n \n seqtk\n \n \'$output1\'\n ]]>\n \n \n \n \n \n \n \n \n \n \n \n \n |\n\nOptions: -q INT mask bases with quality lower than INT [0]\n -X INT mask bases with quality higher than INT [255]\n -n CHAR masked bases converted to CHAR; 0 for lowercase [0]\n -l INT number of residues per line; 0 for 2^32-1 [0]\n -Q INT quality shift: ASCII-INT gives base quality [33]\n -s INT random seed (effective with -f) [11]\n -f FLOAT sample FLOAT fraction of sequences [1]\n -M FILE mask regions in BED or name list FILE [null]\n -L INT drop sequences with length shorter than INT [0]\n -c mask complement region (effective with -M)\n -r reverse complement\n -A force FASTA output (discard quality)\n -C drop comments at the header lines\n -N drop sequences containing ambiguous bases\n -1 output the 2n-1 reads only\n -2 output the 2n reads only\n -V shift quality by \'(-Q) - 33\'\n -U convert all bases to uppercases\n -S strip of white spaces in sequences\n\n\n ]]>\n \n \n@misc{githubseqtk,\n author = {LastTODO, FirstTODO},\n year = {TODO},\n title = {seqtk},\n publisher = {GitHub},\n journal = {GitHub repository},\n url = {https://github.com/lh3/seqtk},\n}\n \n\n至此,我们有了一个功能相当齐全的 Galaxy 工具,它带有测试和帮助。这是一个非常简单的示例——通常,您需要在工具中投入更多工作才能实现这一点, tool_init 实际上只是为了让您入门而设计的。\n现在让我们检查并测试我们开发的工具。Planemo的 lint(或仅 l )命令将检查工具的 XML 有效性,检查是否有明显的错误以及是否符合 IUC 的最佳做法。\n$ planemo l\nLinting tool /opt/galaxy/tools/seqtk_seq.xml\nApplying linter tests... CHECK\n.. CHECK: 1 test(s) found.\nApplying linter output... CHECK\n.. INFO: 1 outputs found.\nApplying linter inputs... CHECK\n.. INFO: Found 1 input parameters.\nApplying linter help... CHECK\n.. CHECK: Tool contains help section.\n.. CHECK: Help contains valid reStructuredText.\nApplying linter general... CHECK\n.. CHECK: Tool defines a version [0.1.0].\n.. CHECK: Tool defines a name [Convert to FASTA (seqtk)].\n.. CHECK: Tool defines an id [seqtk_seq].\n.. CHECK: Tool targets 16.01 Galaxy profile.\nApplying linter command... CHECK\n.. INFO: Tool contains a command.\nApplying linter citations... CHECK\n.. CHECK: Found 1 likely valid citations.\nApplying linter tool_xsd... CHECK\n.. INFO: File validates against XML schema.\n默认情况下, lint 会在您当前的工作目录中找到所有工具,但是我们可以使用 planemo lint seqtk_seq.xml 指定一个特定的工具。\n接下来,我们可以使用 test(或仅执行 t )命令运行工具的功能测试。这将打印很多输出(因为它启动了 Galaxy 实例),但最终应该显示我们通过的一项测试。\n\n如果你的服务器已经安装了 Galaxy 实例,你可以编辑 ~/.planemo.yml 文件,指定 Galaxy 实例路径。\n\n## Specify a default galaxy_root for the `test` and `serve` commands here.\ngalaxy_root: /home/user/galaxy\n\n完整的 ~/.planemo.yml 示例,参考:https://planemo.readthedocs.io/en/latest/configuration.html\n\n$ planemo t\n...\nAll 1 test(s) executed passed.\nseqtk_seq[0]: passed\n除了在控制台中将测试结果显示为红色(失败)或绿色(通过)外,Planemo 还默认为测试结果创建 HTML 报告。 还有更多测试报告选项可用,例如 --test_output_xunit,在某些持续集成环境中很有用。有关更多选项,请参见 planemo test --help ,以及 test_reports 命令。\n现在,我们可以使用 serve(或仅使用 s )命令打开 Galaxy。\n$ planemo s\n...\nserving on http://127.0.0.1:9090\n在网络浏览器中打开 http://127.0.0.1:9090 以查看您的新工具。\n服务和测试可以通过各种命令行参数传递,例如 --galaxy_root,以指定要使用的 Galaxy 实例(默认情况下,planemo 将仅为 planemo 下载和管理实例)。\n简单参数\n我们为 seqtk seq 命令构建了一个工具包的封装,但是该工具实际上具有我们可能希望向 Galaxy 用户公开的其他选项。\n让我们从 help 命令中获取一些参数,并构建 Galaxy 的 param 块以粘贴到该工具的 input 块中。\n-V shift quality by \'(-Q) - 33\'\n在上一节中,我们看到了输入文件在 param 块中是一个 data 的类型,除此之外我们还可以使用许多不同种类的参数。如标志参数(例如以上 -V 参数),通常在 Galaxy 工具的 XML 文件中由 boolean 来表示。\n\n然后,我们可以将 $shift_quality 粘贴在 command 块中,如果用户选择了此选项,它将扩展为 -V (因为我们已将其定义为 truevalue )。如果用户未选择此选项,则 $shift_quality 将仅扩展为空字符串,而不会影响生成的命令行。\n现在考虑以下的 seqtk seq 参数:\n-q INT mask bases with quality lower than INT [0]\n-X INT mask bases with quality higher than INT [255]\n这些可以转换为 Galaxy 参数,如下所示:\n\n\n这些可以作为 -q $quality_min -X $quality_max 添加到命令标签中。\n此时,该工具将如下所示:\n\n \n seqtk\n \n \'$output1\'\n ]]>\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n |\n\nOptions: -q INT mask bases with quality lower than INT [0]\n -X INT mask bases with quality higher than INT [255]\n -n CHAR masked bases converted to CHAR; 0 for lowercase [0]\n -l INT number of residues per line; 0 for 2^32-1 [0]\n -Q INT quality shift: ASCII-INT gives base quality [33]\n -s INT random seed (effective with -f) [11]\n -f FLOAT sample FLOAT fraction of sequences [1]\n -M FILE mask regions in BED or name list FILE [null]\n -L INT drop sequences with length shorter than INT [0]\n -c mask complement region (effective with -M)\n -r reverse complement\n -A force FASTA output (discard quality)\n -C drop comments at the header lines\n -N drop sequences containing ambiguous bases\n -1 output the 2n-1 reads only\n -2 output the 2n reads only\n -V shift quality by \'(-Q) - 33\'\n -U convert all bases to uppercases\n\n\n ]]>\n \n \n@misc{githubseqtk,\n author = {LastTODO, FirstTODO},\n year = {TODO},\n title = {seqtk},\n publisher = {GitHub},\n journal = {GitHub repository},\n url = {https://github.com/lh3/seqtk},\n}\n \n\n条件参数\n以前的参数很简单,因为它们总是出现,现在考虑一下下面的参数。\n-M FILE mask regions in BED or name list FILE [null]\n我们可以通过添加属性 optional ="true" 将该数据类型参数标记为可选。\n\n然后,不仅可以直接在命令块中使用 $mask_regions,还可以将其包装在 if 语句中(因为工具 XML 文件支持 Cheetah)。\n#if $mask_regions\n-M \'$mask_regions\'\n#end if\n接着,我们考虑这一组参数:\n-s INT random seed (effective with -f) [11]\n-f FLOAT sample FLOAT fraction of sequences [1]\n在这种情况下,只有在设置了样本参数的情况下,才能看到或使用 -s 随机种子参数。我们可以使用 conditional 条件块来表达这一点。\n\n \n \n \n \n \n \n \n\n在命令块中,我们可以再次使用 if 语句包括这些参数。\n#if $sample.sample_selector\n-f $sample.fraction -s $sample.seed\n#end if\n注意,我们必须使用 sample. 的前缀来引用这个参数,因为它们是在 sample 的条件块内定义的。\n现在该工具的最新版本如下:\n\n \n seqtk\n \n \'$output1\'\n ]]>\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n |\n\nOptions: -q INT mask bases with quality lower than INT [0]\n -X INT mask bases with quality higher than INT [255]\n -n CHAR masked bases converted to CHAR; 0 for lowercase [0]\n -l INT number of residues per line; 0 for 2^32-1 [0]\n -Q INT quality shift: ASCII-INT gives base quality [33]\n -s INT random seed (effective with -f) [11]\n -f FLOAT sample FLOAT fraction of sequences [1]\n -M FILE mask regions in BED or name list FILE [null]\n -L INT drop sequences with length shorter than INT [0]\n -c mask complement region (effective with -M)\n -r reverse complement\n -A force FASTA output (discard quality)\n -C drop comments at the header lines\n -N drop sequences containing ambiguous bases\n -1 output the 2n-1 reads only\n -2 output the 2n reads only\n -V shift quality by \'(-Q) - 33\'\n -U convert all bases to uppercases\n\n\n ]]>\n \n \n@misc{githubseqtk,\n author = {LastTODO, FirstTODO},\n year = {TODO},\n title = {seqtk},\n publisher = {GitHub},\n journal = {GitHub repository},\n url = {https://github.com/lh3/seqtk},\n}\n \n\n对于这样的工具,这些工具有很多选项,但在大多数情况下使用默认值是首选——一个常见的习惯用法是使用条件将参数分为简单部分和高级部分。\n使用惯用法,更新此工具后的 XML 如下所示:\n\n \n seqtk\n \n \'$output1\'\n ]]>\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n |\n\nOptions: -q INT mask bases with quality lower than INT [0]\n -X INT mask bases with quality higher than INT [255]\n -n CHAR masked bases converted to CHAR; 0 for lowercase [0]\n -l INT number of residues per line; 0 for 2^32-1 [0]\n -Q INT quality shift: ASCII-INT gives base quality [33]\n -s INT random seed (effective with -f) [11]\n -f FLOAT sample FLOAT fraction of sequences [1]\n -M FILE mask regions in BED or name list FILE [null]\n -L INT drop sequences with length shorter than INT [0]\n -c mask complement region (effective with -M)\n -r reverse complement\n -A force FASTA output (discard quality)\n -C drop comments at the header lines\n -N drop sequences containing ambiguous bases\n -1 output the 2n-1 reads only\n -2 output the 2n reads only\n -V shift quality by \'(-Q) - 33\'\n -U convert all bases to uppercases\n\n\n ]]>\n \n \n@misc{githubseqtk,\n author = {LastTODO, FirstTODO},\n year = {TODO},\n title = {seqtk},\n publisher = {GitHub},\n journal = {GitHub repository},\n url = {https://github.com/lh3/seqtk},\n}\n \n\n脚本封装\nTool Shed 上已经提供了许多常见的生物信息学应用程序,因此一项常见的开发任务是将各种复杂程度的脚本集成到 Galaxy 中。\n考虑以下小型 Perl 脚本。\n#!/usr/bin/perl -w\n\n# usage : perl toolExample.pl \n\nopen (IN, "<$ARGV[0]");\nopen (OUT, ">$ARGV[1]");\nwhile () {\n chop;\n if (m/^>/) {\n s/^>//;\n if ($. > 1) {\n print OUT sprintf("%.3f", $gc/$length) . "\\n";\n }\n $gc = 0;\n $length = 0;\n } else {\n ++$gc while m/[gc]/ig;\n $length += length $_;\n }\n}\nprint OUT sprintf("%.3f", $gc/$length) . "\\n";\nclose( IN );\nclose( OUT );\n可以按照以下步骤为此脚本构建 Galaxy 工具,并将脚本与工具 XML 文件本身放在同一目录中。这里的特殊值 $__ tool_directory__ 是指工具(即 xml 文件)所在的目录。\n\n for each sequence in a file\n perl \'$__tool_directory__/gc_content.pl\' \'$input\' output.tsv\n \n \n \n \n \n \n \nThis tool computes GC content from a FASTA file.\n \n\nMacros 宏集\n如果您希望为单个相对简单的应用程序或脚本编写工具,则应跳过本节。如果您希望维护一系列相关工具——经验表明,您将意识到有很多重复的 XML 可以很好地做到这一点。Galaxy工具 XML 宏可以帮助减少这种重复。\n通过使用 --macros 标志,Planemo 的 tool_init 命令可用于生成适合工具套件的宏文件。我们看一下以前的 tool_init 命令的变体(唯一的区别是现在我们添加了 --macros 标志)。\n$ planemo tool_init --force \\\n --macros \\\n --id \'seqtk_seq\' \\\n --name \'Convert to FASTA (seqtk)\' \\\n --requirement seqtk@1.2 \\\n --example_command \'seqtk seq -A 2.fastq > 2.fasta\' \\\n --example_input 2.fastq \\\n --example_output 2.fasta \\\n --test_case \\\n --help_from_command \'seqtk seq\'\n这将在当前目录中产生两个文件( seqtk_seq.xml 和 macros.xml),而不是一个。\n\n \n macros.xml\n \n \n \'$output1\'\n ]]>\n \n \n \n \n \n \n \n \n \n \n \n \n |\n\nOptions: -q INT mask bases with quality lower than INT [0]\n -X INT mask bases with quality higher than INT [255]\n -n CHAR masked bases converted to CHAR; 0 for lowercase [0]\n -l INT number of residues per line; 0 for 2^32-1 [0]\n -Q INT quality shift: ASCII-INT gives base quality [33]\n -s INT random seed (effective with -f) [11]\n -f FLOAT sample FLOAT fraction of sequences [1]\n -M FILE mask regions in BED or name list FILE [null]\n -L INT drop sequences with length shorter than INT [0]\n -c mask complement region (effective with -M)\n -r reverse complement\n -A force FASTA output (discard quality)\n -C drop comments at the header lines\n -N drop sequences containing ambiguous bases\n -1 output the 2n-1 reads only\n -2 output the 2n reads only\n -V shift quality by \'(-Q) - 33\'\n -U convert all bases to uppercases\n -S strip of white spaces in sequences\n\n\n ]]>\n \n\n\n \n \n seqtk\n \n \n \n \n \n \n \n \n\n如您在上面的代码中所看到的,宏是可重用的 XML 块,它们使避免重复和保持 XML 简洁变得更加容易。\n参考资料\n\nMacros syntax on the Galaxy Wiki.\nGATK tools (example tools making extensive use of macros)\ngemini tools (example tools making extensive use of macros)\nbedtools tools (example tools making extensive use of macros)\nMacros implementation details - Pull Request #129 and Pull Request #140\nGalaxy’s Tool XML Syntax\nBig List of Tool Development Resources\nCheetah templating', 'bodyHTML': '
\n

说明:本文章原文发布于 《使用 Planemo 进行 Galaxy 工具开发 - 语雀》,部分内容已更新。

\n
\n

文章开始前,我们先了解一下 Planemo 到底是个什么东西。

\n
\n

Command-line utilities to assist in developing Galaxy and Common Workflow Language artifacts - including tools, workflows, and training materials.

\n
\n

说白了,Planemo 就是用于 Galaxy 平台工具和 WDL 通用工作流语言相关产品辅助开发的一个命令行工具,这个程序集可以用于工具、流程,以及培训教材的开发。

\n\n

安装 Planemo

\n

无论是 pip 还是 conda 都可以安装 Planemo:

\n
$ pip install planemo\n$ pip install -U git+git://github.com/galaxyproject/planemo.git
\n
$ conda config --add channels bioconda\n$ conda config --add channels conda-forge\n$ conda install planemo
\n

接下来,进入今天的正题,我们来详细介绍一下怎么使用 Planemo 进行 Galaxy 工具开发。

\n

基础用法

\n

本指南将演示如何使用 Heng Li 的 Seqtk 软件包构建命令工具,该软件包用于处理 FASTA 和 FASTQ 文件中的序列数据。

\n

首先,我们需要先安装 Seqtk 。在这里,我们使用 conda 来安装 Seqtk (你也可以使用其他的方法安装)。

\n
$ conda install --force --yes -c conda-forge -c bioconda seqtk=1.2\n    ... seqtk installation ...\n$ seqtk seq\n        Usage:   seqtk seq [options] <in.fq>|<in.fa>\n        Options: -q INT    mask bases with quality lower than INT [0]\n                 -X INT    mask bases with quality higher than INT [255]\n                 -n CHAR   masked bases converted to CHAR; 0 for lowercase [0]\n                 -l INT    number of residues per line; 0 for 2^32-1 [0]\n                 -Q INT    quality shift: ASCII-INT gives base quality [33]\n                 -s INT    random seed (effective with -f) [11]\n                 -f FLOAT  sample FLOAT fraction of sequences [1]\n                 -M FILE   mask regions in BED or name list FILE [null]\n                 -L INT    drop sequences with length shorter than INT [0]\n                 -c        mask complement region (effective with -M)\n                 -r        reverse complement\n                 -A        force FASTA output (discard quality)\n                 -C        drop comments at the header lines\n                 -N        drop sequences containing ambiguous bases\n                 -1        output the 2n-1 reads only\n                 -2        output the 2n reads only\n                 -V        shift quality by \'(-Q) - 33\'
\n

接下来,我们将下载一个 FASTQ 示例文件,并测试一个简单的 Seqtk 命令 seq ,该命令将 FASTQ 文件转换为 FASTA。

\n
$ wget https://raw.githubusercontent.com/galaxyproject/galaxy-test-data/master/2.fastq\n$ seqtk seq -A 2.fastq > 2.fasta\n$ cat 2.fasta\n>EAS54_6_R1_2_1_413_324\nCCCTTCTTGTCTTCAGCGTTTCTCC\n>EAS54_6_R1_2_1_540_792\nTTGGCAGGCCAAGGCCGATGGATCA\n>EAS54_6_R1_2_1_443_348\nGTTGCTTCTGGCGTGGGTGGGGGGG
\n

有关功能齐全的 Seqtk 包封装,可以在 GitHub 上查看 Helena Rasche\'s wrappers

\n

Galaxy 工具文件只是 XML 文件,因此此时可以打开文本编辑器并开始编写工具。Planemo 有一个命令 tool_init 可以快速生成一些样板 XML,因此首先开始。

\n
$ planemo tool_init --id \'seqtk_seq\' --name \'Convert to FASTA (seqtk)\'
\n

tool_init 命令可以采用各种复杂的参数,但如上面展示的 --id--name 是其中两个最基本的参数。每个 Galaxy 工具都需要一个 ID(这是 Galaxy 自身用来标识该工具的简短标识符)和一个名称(此名称会显示给 Galaxy 用户,并且应该是该工具的简短描述)。工具名称可以包含空格,但其 ID 不能包含空格。

\n

上面的命令将生成一个 seqtk_seq.xml 文件,这个文件看起来像这样:

\n
<tool id="seqtk_seq" name="Convert to FASTA (seqtk)" version="0.1.0" python_template_version="3.5">\n    <requirements>\n    </requirements>\n    <command detect_errors="exit_code"><![CDATA[\n        TODO: Fill in command template.\n    ]]></command>\n    <inputs>\n    </inputs>\n    <outputs>\n    </outputs>\n    <help><![CDATA[\n        TODO: Fill in help.\n    ]]></help>\n</tool>
\n

这个生成的模板 XML 文件具有了 Galaxy 工具所需的公共部分内容,但你仍然需要打开编辑器并填写命令模板、输入参数描述、工具输出信息、帮助部分信息等。

\n

tool_init 命令也可以做得更好。 们可以使用在 seqtk seq -a 2.fastq> 2.fasta 上面尝试过的测试命令作为示例,通过指定输入和输出来生成命令块,如下所示。

\n
$ planemo tool_init --force \\\n                    --id \'seqtk_seq\' \\\n                    --name \'Convert to FASTA (seqtk)\' \\\n                    --requirement seqtk@1.2 \\\n                    --example_command \'seqtk seq -a 2.fastq > 2.fasta\' \\\n                    --example_input 2.fastq \\\n                    --example_output 2.fasta
\n

这将生成以下 XML 文件- 该文件具有正确的输入和输出定义以及实际的命令模板。

\n
<tool id="seqtk_seq" name="Convert to FASTA (seqtk)" version="0.1.0" python_template_version="3.5">\n    <requirements>\n        <requirement type="package" version="1.2">seqtk</requirement>\n    </requirements>\n    <command detect_errors="exit_code"><![CDATA[\n        seqtk seq -a \'$input1\' > \'$output1\'\n    ]]></command>\n    <inputs>\n        <param type="data" name="input1" format="fastq" />\n    </inputs>\n    <outputs>\n        <data name="output1" format="fasta" />\n    </outputs>\n    <help><![CDATA[\n        TODO: Fill in help.\n    ]]></help>\n</tool>(
\n

如本节开头所示,命令 seqtk seq 会为 seq 命令生成帮助消息。 tool_init 可以获取该帮助消息,并使用 help_from_command 选项将其正确粘贴在生成的工具 XML 文件中。

\n

通常,命令帮助消息并不完全适用于工具,因为它们会提到参数名称和由工具抽象出来的类似细节,但它们可能是一个很好的起点。

\n

以下 Planemo 的 tool_init 的调用已增强为使用 --help_from_command

\n
$ planemo tool_init --force \\\n                    --id \'seqtk_seq\' \\\n                    --name \'Convert to FASTA (seqtk)\' \\\n                    --requirement seqtk@1.2 \\\n                    --example_command \'seqtk seq -a 2.fastq > 2.fasta\' \\\n                    --example_input 2.fastq \\\n                    --example_output 2.fasta \\\n                    --test_case \\\n                    --cite_url \'https://github.com/lh3/seqtk\' \\\n                    --help_from_command \'seqtk seq\'
\n

除了演示 --help_from_command 之外,这还演示了使用 --test_case 从我们的示例生成测试用例并为基础工具添加引用。生成的工具 XML 文件为:

\n
<tool id="seqtk_seq" name="Convert to FASTA (seqtk)" version="0.1.0" python_template_version="3.5">\n    <requirements>\n        <requirement type="package" version="1.2">seqtk</requirement>\n    </requirements>\n    <command detect_errors="exit_code"><![CDATA[\n        seqtk seq -a \'$input1\' > \'$output1\'\n    ]]></command>\n    <inputs>\n        <param type="data" name="input1" format="fastq" />\n    </inputs>\n    <outputs>\n        <data name="output1" format="fasta" />\n    </outputs>\n    <tests>\n        <test>\n            <param name="input1" value="2.fastq"/>\n            <output name="output1" file="2.fasta"/>\n        </test>\n    </tests>\n    <help><![CDATA[\n\nUsage:   seqtk seq [options] <in.fq>|<in.fa>\n\nOptions: -q INT    mask bases with quality lower than INT [0]\n         -X INT    mask bases with quality higher than INT [255]\n         -n CHAR   masked bases converted to CHAR; 0 for lowercase [0]\n         -l INT    number of residues per line; 0 for 2^32-1 [0]\n         -Q INT    quality shift: ASCII-INT gives base quality [33]\n         -s INT    random seed (effective with -f) [11]\n         -f FLOAT  sample FLOAT fraction of sequences [1]\n         -M FILE   mask regions in BED or name list FILE [null]\n         -L INT    drop sequences with length shorter than INT [0]\n         -c        mask complement region (effective with -M)\n         -r        reverse complement\n         -A        force FASTA output (discard quality)\n         -C        drop comments at the header lines\n         -N        drop sequences containing ambiguous bases\n         -1        output the 2n-1 reads only\n         -2        output the 2n reads only\n         -V        shift quality by \'(-Q) - 33\'\n         -U        convert all bases to uppercases\n         -S        strip of white spaces in sequences\n\n\n    ]]></help>\n    <citations>\n        <citation type="bibtex">\n@misc{githubseqtk,\n  author = {LastTODO, FirstTODO},\n  year = {TODO},\n  title = {seqtk},\n  publisher = {GitHub},\n  journal = {GitHub repository},\n  url = {https://github.com/lh3/seqtk},\n}</citation>\n    </citations>\n</tool>
\n

至此,我们有了一个功能相当齐全的 Galaxy 工具,它带有测试和帮助。这是一个非常简单的示例——通常,您需要在工具中投入更多工作才能实现这一点, tool_init 实际上只是为了让您入门而设计的。

\n

现在让我们检查并测试我们开发的工具。Planemo的 lint(或仅 l )命令将检查工具的 XML 有效性,检查是否有明显的错误以及是否符合 IUC 的最佳做法。

\n
$ planemo l\nLinting tool /opt/galaxy/tools/seqtk_seq.xml\nApplying linter tests... CHECK\n.. CHECK: 1 test(s) found.\nApplying linter output... CHECK\n.. INFO: 1 outputs found.\nApplying linter inputs... CHECK\n.. INFO: Found 1 input parameters.\nApplying linter help... CHECK\n.. CHECK: Tool contains help section.\n.. CHECK: Help contains valid reStructuredText.\nApplying linter general... CHECK\n.. CHECK: Tool defines a version [0.1.0].\n.. CHECK: Tool defines a name [Convert to FASTA (seqtk)].\n.. CHECK: Tool defines an id [seqtk_seq].\n.. CHECK: Tool targets 16.01 Galaxy profile.\nApplying linter command... CHECK\n.. INFO: Tool contains a command.\nApplying linter citations... CHECK\n.. CHECK: Found 1 likely valid citations.\nApplying linter tool_xsd... CHECK\n.. INFO: File validates against XML schema.
\n

默认情况下, lint 会在您当前的工作目录中找到所有工具,但是我们可以使用 planemo lint seqtk_seq.xml 指定一个特定的工具。

\n

接下来,我们可以使用 test(或仅执行 t )命令运行工具的功能测试。这将打印很多输出(因为它启动了 Galaxy 实例),但最终应该显示我们通过的一项测试。

\n
\n

如果你的服务器已经安装了 Galaxy 实例,你可以编辑 ~/.planemo.yml 文件,指定 Galaxy 实例路径。

\n
\n
## Specify a default galaxy_root for the `test` and `serve` commands here.\ngalaxy_root: /home/user/galaxy
\n
\n

完整的 ~/.planemo.yml 示例,参考:https://planemo.readthedocs.io/en/latest/configuration.html

\n
\n
$ planemo t\n...\nAll 1 test(s) executed passed.\nseqtk_seq[0]: passed
\n

除了在控制台中将测试结果显示为红色(失败)或绿色(通过)外,Planemo 还默认为测试结果创建 HTML 报告。 还有更多测试报告选项可用,例如 --test_output_xunit,在某些持续集成环境中很有用。有关更多选项,请参见 planemo test --help ,以及 test_reports 命令。

\n

现在,我们可以使用 serve(或仅使用 s )命令打开 Galaxy。

\n
$ planemo s\n...\nserving on http://127.0.0.1:9090
\n

在网络浏览器中打开 http://127.0.0.1:9090 以查看您的新工具。

\n

服务和测试可以通过各种命令行参数传递,例如 --galaxy_root,以指定要使用的 Galaxy 实例(默认情况下,planemo 将仅为 planemo 下载和管理实例)。

\n

简单参数

\n

我们为 seqtk seq 命令构建了一个工具包的封装,但是该工具实际上具有我们可能希望向 Galaxy 用户公开的其他选项。

\n

让我们从 help 命令中获取一些参数,并构建 Galaxy 的 param 块以粘贴到该工具的 input 块中。

\n
-V        shift quality by \'(-Q) - 33\'
\n

在上一节中,我们看到了输入文件在 param 块中是一个 data 的类型,除此之外我们还可以使用许多不同种类的参数。如标志参数(例如以上 -V 参数),通常在 Galaxy 工具的 XML 文件中由 boolean 来表示。

\n
<param name="shift_quality" type="boolean" label="Shift quality"\n       truevalue="-V" falsevalue=""\n       help="shift quality by \'(-Q) - 33\' (-V)" />
\n

然后,我们可以将 $shift_quality 粘贴在 command 块中,如果用户选择了此选项,它将扩展为 -V (因为我们已将其定义为 truevalue )。如果用户未选择此选项,则 $shift_quality 将仅扩展为空字符串,而不会影响生成的命令行。

\n

现在考虑以下的 seqtk seq 参数:

\n
-q INT    mask bases with quality lower than INT [0]\n-X INT    mask bases with quality higher than INT [255]
\n

这些可以转换为 Galaxy 参数,如下所示:

\n
<param name="quality_min" type="integer" label="Mask bases with quality lower than"\n       value="0" min="0" max="255" help="(-q)" />\n<param name="quality_max" type="integer" label="Mask bases with quality higher than"\n       value="255" min="0" max="255" help="(-X)" />
\n

这些可以作为 -q $quality_min -X $quality_max 添加到命令标签中。

\n

此时,该工具将如下所示:

\n
<tool id="seqtk_seq" name="Convert to FASTA (seqtk)" version="0.1.0" python_template_version="3.5">\n    <requirements>\n        <requirement type="package" version="1.2">seqtk</requirement>\n    </requirements>\n    <command detect_errors="exit_code"><![CDATA[\n        seqtk seq\n              $shift_quality\n              -q $quality_min\n              -X $quality_max\n              -a \'$input1\' > \'$output1\'\n    ]]></command>\n    <inputs>\n        <param type="data" name="input1" format="fastq" />\n        <param name="shift_quality" type="boolean" label="Shift quality" \n               truevalue="-V" falsevalue=""\n               help="shift quality by \'(-Q) - 33\' (-V)" />\n        <param name="quality_min" type="integer" label="Mask bases with quality lower than" \n               value="0" min="0" max="255" help="(-q)" />\n        <param name="quality_max" type="integer" label="Mask bases with quality higher than" \n               value="255" min="0" max="255" help="(-X)" />\n    </inputs>\n    <outputs>\n        <data name="output1" format="fasta" />\n    </outputs>\n    <tests>\n        <test>\n            <param name="input1" value="2.fastq"/>\n            <output name="output1" file="2.fasta"/>\n        </test>\n    </tests>\n    <help><![CDATA[\n        \nUsage:   seqtk seq [options] <in.fq>|<in.fa>\n\nOptions: -q INT    mask bases with quality lower than INT [0]\n         -X INT    mask bases with quality higher than INT [255]\n         -n CHAR   masked bases converted to CHAR; 0 for lowercase [0]\n         -l INT    number of residues per line; 0 for 2^32-1 [0]\n         -Q INT    quality shift: ASCII-INT gives base quality [33]\n         -s INT    random seed (effective with -f) [11]\n         -f FLOAT  sample FLOAT fraction of sequences [1]\n         -M FILE   mask regions in BED or name list FILE [null]\n         -L INT    drop sequences with length shorter than INT [0]\n         -c        mask complement region (effective with -M)\n         -r        reverse complement\n         -A        force FASTA output (discard quality)\n         -C        drop comments at the header lines\n         -N        drop sequences containing ambiguous bases\n         -1        output the 2n-1 reads only\n         -2        output the 2n reads only\n         -V        shift quality by \'(-Q) - 33\'\n         -U        convert all bases to uppercases\n\n\n    ]]></help>\n    <citations>\n        <citation type="bibtex">\n@misc{githubseqtk,\n  author = {LastTODO, FirstTODO},\n  year = {TODO},\n  title = {seqtk},\n  publisher = {GitHub},\n  journal = {GitHub repository},\n  url = {https://github.com/lh3/seqtk},\n}</citation>\n    </citations>\n</tool>
\n

条件参数

\n

以前的参数很简单,因为它们总是出现,现在考虑一下下面的参数。

\n
-M FILE   mask regions in BED or name list FILE [null]
\n

我们可以通过添加属性 optional ="true" 将该数据类型参数标记为可选。

\n
<param name="mask_regions" type="data" label="Mask regions in BED"\n       format="bed" help="(-M)" optional="true" />
\n

然后,不仅可以直接在命令块中使用 $mask_regions,还可以将其包装在 if 语句中(因为工具 XML 文件支持 Cheetah)。

\n
#if $mask_regions\n-M \'$mask_regions\'\n#end if
\n

接着,我们考虑这一组参数:

\n
-s INT    random seed (effective with -f) [11]\n-f FLOAT  sample FLOAT fraction of sequences [1]
\n

在这种情况下,只有在设置了样本参数的情况下,才能看到或使用 -s 随机种子参数。我们可以使用 conditional 条件块来表达这一点。

\n
<conditional name="sample">\n    <param name="sample_selector" type="boolean" label="Sample fraction of sequences" />\n    <when value="true">\n        <param name="fraction" label="Fraction" type="float" value="1.0"\n               help="(-f)" />\n        <param name="seed" label="Random seed" type="integer" value="11"\n               help="(-s)" />\n    </when>\n    <when value="false">\n    </when>\n</conditional>
\n

在命令块中,我们可以再次使用 if 语句包括这些参数。

\n
#if $sample.sample_selector\n-f $sample.fraction -s $sample.seed\n#end if
\n

注意,我们必须使用 sample. 的前缀来引用这个参数,因为它们是在 sample 的条件块内定义的。

\n

现在该工具的最新版本如下:

\n
<tool id="seqtk_seq" name="Convert to FASTA (seqtk)" version="0.1.0" python_template_version="3.5">\n    <requirements>\n        <requirement type="package" version="1.2">seqtk</requirement>\n    </requirements>\n    <command detect_errors="exit_code"><![CDATA[\n        seqtk seq\n              $shift_quality\n              -q $quality_min\n              -X $quality_max\n              #if $mask_regions\n                  -M \'$mask_regions\'\n              #end if\n              #if $sample.sample\n                  -f $sample.fraction\n                  -s $sample.seed\n              #end if\n              -a \'$input1\' > \'$output1\'\n    ]]></command>\n    <inputs>\n        <param type="data" name="input1" format="fastq" />\n        <param name="shift_quality" type="boolean" label="Shift quality" \n               truevalue="-V" falsevalue=""\n               help="shift quality by \'(-Q) - 33\' (-V)" />\n        <param name="quality_min" type="integer" label="Mask bases with quality lower than" \n               value="0" min="0" max="255" help="(-q)" />\n        <param name="quality_max" type="integer" label="Mask bases with quality higher than" \n               value="255" min="0" max="255" help="(-X)" />\n        <param name="mask_regions" type="data" label="Mask regions in BED" \n               format="bed" help="(-M)" optional="true" />\n        <conditional name="sample">\n            <param name="sample" type="boolean" label="Sample fraction of sequences" />\n            <when value="true">\n                <param name="fraction" label="Fraction" type="float" value="1.0"\n                       help="(-f)" />\n                <param name="seed" label="Random seed" type="integer" value="11"\n                       help="(-s)" />\n            </when>\n            <when value="false">\n            </when>\n        </conditional>\n    </inputs>\n    <outputs>\n        <data name="output1" format="fasta" />\n    </outputs>\n    <tests>\n        <test>\n            <param name="input1" value="2.fastq"/>\n            <output name="output1" file="2.fasta"/>\n        </test>\n    </tests>\n    <help><![CDATA[\n        \nUsage:   seqtk seq [options] <in.fq>|<in.fa>\n\nOptions: -q INT    mask bases with quality lower than INT [0]\n         -X INT    mask bases with quality higher than INT [255]\n         -n CHAR   masked bases converted to CHAR; 0 for lowercase [0]\n         -l INT    number of residues per line; 0 for 2^32-1 [0]\n         -Q INT    quality shift: ASCII-INT gives base quality [33]\n         -s INT    random seed (effective with -f) [11]\n         -f FLOAT  sample FLOAT fraction of sequences [1]\n         -M FILE   mask regions in BED or name list FILE [null]\n         -L INT    drop sequences with length shorter than INT [0]\n         -c        mask complement region (effective with -M)\n         -r        reverse complement\n         -A        force FASTA output (discard quality)\n         -C        drop comments at the header lines\n         -N        drop sequences containing ambiguous bases\n         -1        output the 2n-1 reads only\n         -2        output the 2n reads only\n         -V        shift quality by \'(-Q) - 33\'\n         -U        convert all bases to uppercases\n\n\n    ]]></help>\n    <citations>\n        <citation type="bibtex">\n@misc{githubseqtk,\n  author = {LastTODO, FirstTODO},\n  year = {TODO},\n  title = {seqtk},\n  publisher = {GitHub},\n  journal = {GitHub repository},\n  url = {https://github.com/lh3/seqtk},\n}</citation>\n    </citations>\n</tool>
\n

对于这样的工具,这些工具有很多选项,但在大多数情况下使用默认值是首选——一个常见的习惯用法是使用条件将参数分为简单部分和高级部分。

\n

使用惯用法,更新此工具后的 XML 如下所示:

\n
<tool id="seqtk_seq" name="Convert to FASTA (seqtk)" version="0.1.0" python_template_version="3.5">\n    <requirements>\n        <requirement type="package" version="1.2">seqtk</requirement>\n    </requirements>\n    <command detect_errors="exit_code"><![CDATA[\n        seqtk seq\n              #if $settings.advanced == "advanced"\n                  $settings.shift_quality\n                  -q $settings.quality_min\n                  -X $settings.quality_max\n                  #if $settings.mask_regions\n                      -M \'$settings.mask_regions\'\n                  #end if\n                  #if $settings.sample.sample\n                      -f $settings.sample.fraction\n                      -s $settings.sample.seed\n                  #end if\n              #end if\n              -a \'$input1\' > \'$output1\'\n    ]]></command>\n    <inputs>\n        <param type="data" name="input1" format="fastq" />\n        <conditional name="settings">\n            <param name="advanced" type="select" label="Specify advanced parameters">\n                <option value="simple" selected="true">No, use program defaults.</option>\n                <option value="advanced">Yes, see full parameter list.</option>\n            </param>\n            <when value="simple">\n            </when>\n            <when value="advanced">\n                <param name="shift_quality" type="boolean" label="Shift quality" \n                       truevalue="-V" falsevalue=""\n                       help="shift quality by \'(-Q) - 33\' (-V)" />\n                <param name="quality_min" type="integer" label="Mask bases with quality lower than" \n                       value="0" min="0" max="255" help="(-q)" />\n                <param name="quality_max" type="integer" label="Mask bases with quality higher than" \n                       value="255" min="0" max="255" help="(-X)" />\n                <param name="mask_regions" type="data" label="Mask regions in BED" \n                       format="bed" help="(-M)" optional="true" />\n                <conditional name="sample">\n                    <param name="sample" type="boolean" label="Sample fraction of sequences" />\n                    <when value="true">\n                        <param name="fraction" label="Fraction" type="float" value="1.0"\n                               help="(-f)" />\n                        <param name="seed" label="Random seed" type="integer" value="11"\n                               help="(-s)" />\n                    </when>\n                    <when value="false">\n                    </when>\n                </conditional>\n            </when>\n        </conditional>\n    </inputs>\n    <outputs>\n        <data name="output1" format="fasta" />\n    </outputs>\n    <tests>\n        <test>\n            <param name="input1" value="2.fastq"/>\n            <output name="output1" file="2.fasta"/>\n        </test>\n    </tests>\n    <help><![CDATA[\n        \nUsage:   seqtk seq [options] <in.fq>|<in.fa>\n\nOptions: -q INT    mask bases with quality lower than INT [0]\n         -X INT    mask bases with quality higher than INT [255]\n         -n CHAR   masked bases converted to CHAR; 0 for lowercase [0]\n         -l INT    number of residues per line; 0 for 2^32-1 [0]\n         -Q INT    quality shift: ASCII-INT gives base quality [33]\n         -s INT    random seed (effective with -f) [11]\n         -f FLOAT  sample FLOAT fraction of sequences [1]\n         -M FILE   mask regions in BED or name list FILE [null]\n         -L INT    drop sequences with length shorter than INT [0]\n         -c        mask complement region (effective with -M)\n         -r        reverse complement\n         -A        force FASTA output (discard quality)\n         -C        drop comments at the header lines\n         -N        drop sequences containing ambiguous bases\n         -1        output the 2n-1 reads only\n         -2        output the 2n reads only\n         -V        shift quality by \'(-Q) - 33\'\n         -U        convert all bases to uppercases\n\n\n    ]]></help>\n    <citations>\n        <citation type="bibtex">\n@misc{githubseqtk,\n  author = {LastTODO, FirstTODO},\n  year = {TODO},\n  title = {seqtk},\n  publisher = {GitHub},\n  journal = {GitHub repository},\n  url = {https://github.com/lh3/seqtk},\n}</citation>\n    </citations>\n</tool>
\n

脚本封装

\n

Tool Shed 上已经提供了许多常见的生物信息学应用程序,因此一项常见的开发任务是将各种复杂程度的脚本集成到 Galaxy 中。

\n

考虑以下小型 Perl 脚本。

\n
#!/usr/bin/perl -w\n\n# usage : perl toolExample.pl <FASTA file> <output file>\n\nopen (IN, "<$ARGV[0]");\nopen (OUT, ">$ARGV[1]");\nwhile (<IN>) {\n    chop;\n    if (m/^>/) {\n        s/^>//;\n        if ($. > 1) {\n            print OUT sprintf("%.3f", $gc/$length) . "\\n";\n        }\n        $gc = 0;\n        $length = 0;\n    } else {\n        ++$gc while m/[gc]/ig;\n        $length += length $_;\n    }\n}\nprint OUT sprintf("%.3f", $gc/$length) . "\\n";\nclose( IN );\nclose( OUT );
\n

可以按照以下步骤为此脚本构建 Galaxy 工具,并将脚本与工具 XML 文件本身放在同一目录中。这里的特殊值 $__ tool_directory__ 是指工具(即 xml 文件)所在的目录。

\n
<tool id="gc_content" name="Compute GC content">\n  <description>for each sequence in a file</description>\n  <command>perl \'$__tool_directory__/gc_content.pl\' \'$input\' output.tsv</command>\n  <inputs>\n    <param name="input" type="data" format="fasta" label="Source file"/>\n  </inputs>\n  <outputs>\n    <data name="output" format="tabular" from_work_dir="output.tsv" />\n  </outputs>\n  <help>\nThis tool computes GC content from a FASTA file.\n  </help>\n</tool>
\n

Macros 宏集

\n

如果您希望为单个相对简单的应用程序或脚本编写工具,则应跳过本节。如果您希望维护一系列相关工具——经验表明,您将意识到有很多重复的 XML 可以很好地做到这一点。Galaxy工具 XML 宏可以帮助减少这种重复。

\n

通过使用 --macros 标志,Planemo 的 tool_init 命令可用于生成适合工具套件的宏文件。我们看一下以前的 tool_init 命令的变体(唯一的区别是现在我们添加了 --macros 标志)。

\n
$ planemo tool_init --force \\\n                    --macros \\\n                    --id \'seqtk_seq\' \\\n                    --name \'Convert to FASTA (seqtk)\' \\\n                    --requirement seqtk@1.2 \\\n                    --example_command \'seqtk seq -A 2.fastq > 2.fasta\' \\\n                    --example_input 2.fastq \\\n                    --example_output 2.fasta \\\n                    --test_case \\\n                    --help_from_command \'seqtk seq\'
\n

这将在当前目录中产生两个文件( seqtk_seq.xmlmacros.xml),而不是一个。

\n
<tool id="seqtk_seq" name="Convert to FASTA (seqtk)" version="0.1.0" python_template_version="3.5">\n    <macros>\n        <import>macros.xml</import>\n    </macros>\n    <expand macro="requirements" />\n    <command detect_errors="exit_code"><![CDATA[\n        seqtk seq -A \'$input1\' > \'$output1\'\n    ]]></command>\n    <inputs>\n        <param type="data" name="input1" format="fastq" />\n    </inputs>\n    <outputs>\n        <data name="output1" format="fasta" />\n    </outputs>\n    <tests>\n        <test>\n            <param name="input1" value="2.fastq"/>\n            <output name="output1" file="2.fasta"/>\n        </test>\n    </tests>\n    <help><![CDATA[\n\nUsage:   seqtk seq [options] <in.fq>|<in.fa>\n\nOptions: -q INT    mask bases with quality lower than INT [0]\n         -X INT    mask bases with quality higher than INT [255]\n         -n CHAR   masked bases converted to CHAR; 0 for lowercase [0]\n         -l INT    number of residues per line; 0 for 2^32-1 [0]\n         -Q INT    quality shift: ASCII-INT gives base quality [33]\n         -s INT    random seed (effective with -f) [11]\n         -f FLOAT  sample FLOAT fraction of sequences [1]\n         -M FILE   mask regions in BED or name list FILE [null]\n         -L INT    drop sequences with length shorter than INT [0]\n         -c        mask complement region (effective with -M)\n         -r        reverse complement\n         -A        force FASTA output (discard quality)\n         -C        drop comments at the header lines\n         -N        drop sequences containing ambiguous bases\n         -1        output the 2n-1 reads only\n         -2        output the 2n reads only\n         -V        shift quality by \'(-Q) - 33\'\n         -U        convert all bases to uppercases\n         -S        strip of white spaces in sequences\n\n\n    ]]></help>\n    <expand macro="citations" />\n</tool>
\n
<macros>\n    <xml name="requirements">\n        <requirements>\n        <requirement type="package" version="1.2">seqtk</requirement>\n            <yield/>\n        </requirements>\n    </xml>\n    <xml name="citations">\n        <citations>\n            <yield />\n        </citations>\n    </xml>\n</macros>
\n

如您在上面的代码中所看到的,宏是可重用的 XML 块,它们使避免重复和保持 XML 简洁变得更加容易。

\n

参考资料

\n', 'author': {'login': 'shenweiyan'}, 'category': {'name': '3.1-Galaxy'}, 'labels': {'nodes': [{'name': '3.1.x-GalaxyOther'}]}, 'comments': {'nodes': []}}, {'title': '越来越难用的国内代码托管平台', 'number': 56, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/56', 'createdAt': '2024-02-02T03:26:02Z', 'lastEditedAt': '2024-02-04T00:48:19Z', 'updatedAt': '2024-02-04T00:48:19Z', 'body': '国内的代码平台对个人用户极其不友好,GitHub 可用的情况下,还是继续用着 GitHub 吧。\r\n\r\n\r\n\r\n## 码云\r\n\r\nGitee 的 Issues 永远都无法搜索内容 - ,感觉社区版本已经在摆烂了,现在他们的重点已经放在了企业版本,但是企业版本又难用的要死!\r\n\r\n## 扣钉\r\n\r\nCoding 现在的页面逻辑我是已经搞不明白了,注销的组织名称永远无法释放不说,在代码仓库更是连 Issues 都去掉了......\r\n\r\n## 极狐\r\n\r\n单是从体验上来说,背靠着 Gitlab 的 [极狐(GitLab)](https://gitlab.cn/) 其实做的还不错,虽然也还没有 APP。 \r\n- [极狐 GitLab 怎么样好不好_极狐 GitLab 优势有哪些-极狐 GitLab](https://gitlab.cn/is-it-any-good/) \r\n- [极狐 GitLab vs GitLab vs GitHub vs Gitee](https://gitlab.cn/comparison/) \r\n![gitlab-jh](https://shub.weiyan.tech/kgarden/2024/02/jihulab-vs-github-gitee.png)\r\n\r\n但是,现在问题来了,极狐从[2024年1月2日起开始要收费了](https://gitlab.cn/blog/2023/11/29/saas-adjustment/),这又是一个昙花一现可以放弃的托管平台,即使付费也总让人感觉这个平台套路不少。\r\n\r\n## 最后\r\n\r\n最后,对于国内的代码托管平台的一个感受 —— 对个人用户极其不友好,都热衷去倒腾企业的版本了,所以,GitHub 可用的情况下,还是继续用着 GitHub 吧;某些情况下登录不上 GitHub 了,国内的 GitCode 作为备用暂时凑合着用吧;至于 Gitee/Coding/Jihulab,还是不要浪费时间去折腾了。', 'bodyText': '国内的代码平台对个人用户极其不友好,GitHub 可用的情况下,还是继续用着 GitHub 吧。\n\n码云\nGitee 的 Issues 永远都无法搜索内容 - https://gitee.com/oschina/git-osc/issues/I7T4W6,感觉社区版本已经在摆烂了,现在他们的重点已经放在了企业版本,但是企业版本又难用的要死!\n扣钉\nCoding 现在的页面逻辑我是已经搞不明白了,注销的组织名称永远无法释放不说,在代码仓库更是连 Issues 都去掉了......\n极狐\n单是从体验上来说,背靠着 Gitlab 的 极狐(GitLab) 其实做的还不错,虽然也还没有 APP。\n\n极狐 GitLab 怎么样好不好_极狐 GitLab 优势有哪些-极狐 GitLab\n极狐 GitLab vs GitLab vs GitHub vs Gitee\n\n\n但是,现在问题来了,极狐从2024年1月2日起开始要收费了,这又是一个昙花一现可以放弃的托管平台,即使付费也总让人感觉这个平台套路不少。\n最后\n最后,对于国内的代码托管平台的一个感受 —— 对个人用户极其不友好,都热衷去倒腾企业的版本了,所以,GitHub 可用的情况下,还是继续用着 GitHub 吧;某些情况下登录不上 GitHub 了,国内的 GitCode 作为备用暂时凑合着用吧;至于 Gitee/Coding/Jihulab,还是不要浪费时间去折腾了。', 'bodyHTML': '

国内的代码平台对个人用户极其不友好,GitHub 可用的情况下,还是继续用着 GitHub 吧。

\n\n

码云

\n

Gitee 的 Issues 永远都无法搜索内容 - https://gitee.com/oschina/git-osc/issues/I7T4W6,感觉社区版本已经在摆烂了,现在他们的重点已经放在了企业版本,但是企业版本又难用的要死!

\n

扣钉

\n

Coding 现在的页面逻辑我是已经搞不明白了,注销的组织名称永远无法释放不说,在代码仓库更是连 Issues 都去掉了......

\n

极狐

\n

单是从体验上来说,背靠着 Gitlab 的 极狐(GitLab) 其实做的还不错,虽然也还没有 APP。

\n\n

但是,现在问题来了,极狐从2024年1月2日起开始要收费了,这又是一个昙花一现可以放弃的托管平台,即使付费也总让人感觉这个平台套路不少。

\n

最后

\n

最后,对于国内的代码托管平台的一个感受 —— 对个人用户极其不友好,都热衷去倒腾企业的版本了,所以,GitHub 可用的情况下,还是继续用着 GitHub 吧;某些情况下登录不上 GitHub 了,国内的 GitCode 作为备用暂时凑合着用吧;至于 Gitee/Coding/Jihulab,还是不要浪费时间去折腾了。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '从公众号到个人独立站点', 'number': 55, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/55', 'createdAt': '2024-01-25T12:28:05Z', 'lastEditedAt': '2024-01-25T12:29:50Z', 'updatedAt': '2024-01-25T12:29:50Z', 'body': '从 2023 年下半年以来 "**BioIT爱好者**" 这个公众号基本上很少更新了,这一点在《[公众号许久没有更新了](https://github.com/shenweiyan/Knowledge-Garden/discussions/28)》就提到过,现在唯一有所区别的是在 [GitHub Discussions](https://github.com/shenweiyan/Knowledge-Garden/discussions/) 的基础上又多了一个个人的独立站点。\r\n\r\n\r\n\r\n![weiyan-cc-home](https://shub.weiyan.tech/kgarden/2024/01/weiyan-cc-home.png)\r\n\r\n![weiyan-cc-hblog](https://shub.weiyan.tech/kgarden/2024/01/weiyan-cc-blog.png)\r\n\r\n全面拥抱 GitHub 的感觉真的很好,加上手机 APP 的加持,更加如虎添翼。回归了最原始 markdown 的编辑和写作,也终于不用再担心在《[富文本编辑器与 md 语法的一些困惑](https://github.com/shenweiyan/Knowledge-Garden/discussions/26)》中所顾虑的问题。\r\n\r\n从 GitHub 到选择 Material for MkDocs 作为个人博客+文档独立站点,有很多的影响因素,但数据可控算是比较核心的一个出发点。这半年来混迹 GitHub 的确也收获良多,发现了很多[有意思的博客和站点](https://github.com/shenweiyan/Knowledge-Garden/discussions/41),学习到了很多优秀的项目。很多时候阅读别人的博客(站点),总能发现一些好玩的人和事物。\r\n\r\n2023 年被[椒盐豆豉](https://blog.douchi.space/)的一篇《[2023 年了你为什么需要写博客](https://blog.douchi.space/2023-why-you-need-a-blog/)》所吸引,尤其是 "博客是赛博空间的另一个你,也能反过来定义你" 这一句,写出了很多心声。\r\n\r\n> 比较反感 "个人品牌" 这个过于商业化的说法,不写技术不写学术的非实名博客甚至起不到简历作用。但它确是比简历更 "像个人",比碎片化社交网络更全面展现我是怎样一个人的网络门面。当然这是我这个博客的用法,网上靠博客经营自己品牌的也比比皆是。总之,内容的自由度和高度的定制化让博客可以成为任何你想让它成为的东西。反之,博客写的久了,发现 "写博客" 也已经成为了自己(不只是线上) identity 的一部分——毕竟这是很多人认识我的渠道,也重塑了我的一部分自我认知。\r\n\r\n虽然期间尝试过《[飞书文档初体验](https://github.com/shenweiyan/Knowledge-Garden/discussions/11)》,从国内版本的飞书到 LarkSuite,但终究不如 GitHub + Material for MkDocs 组合来得顺畅。GitHub 也好,飞书也罢,各种五花八门的奇淫巧技和折腾组合,总有能玩出花来的一波人,找到自己喜欢的并持之以恒就已经足够。\r\n\r\n趁着今天有时间,在公众号同步了这一篇,希望我们不忘初心,做到最好。', 'bodyText': '从 2023 年下半年以来 "BioIT爱好者" 这个公众号基本上很少更新了,这一点在《公众号许久没有更新了》就提到过,现在唯一有所区别的是在 GitHub Discussions 的基础上又多了一个个人的独立站点。\n\n\n\n全面拥抱 GitHub 的感觉真的很好,加上手机 APP 的加持,更加如虎添翼。回归了最原始 markdown 的编辑和写作,也终于不用再担心在《富文本编辑器与 md 语法的一些困惑》中所顾虑的问题。\n从 GitHub 到选择 Material for MkDocs 作为个人博客+文档独立站点,有很多的影响因素,但数据可控算是比较核心的一个出发点。这半年来混迹 GitHub 的确也收获良多,发现了很多有意思的博客和站点,学习到了很多优秀的项目。很多时候阅读别人的博客(站点),总能发现一些好玩的人和事物。\n2023 年被椒盐豆豉的一篇《2023 年了你为什么需要写博客》所吸引,尤其是 "博客是赛博空间的另一个你,也能反过来定义你" 这一句,写出了很多心声。\n\n比较反感 "个人品牌" 这个过于商业化的说法,不写技术不写学术的非实名博客甚至起不到简历作用。但它确是比简历更 "像个人",比碎片化社交网络更全面展现我是怎样一个人的网络门面。当然这是我这个博客的用法,网上靠博客经营自己品牌的也比比皆是。总之,内容的自由度和高度的定制化让博客可以成为任何你想让它成为的东西。反之,博客写的久了,发现 "写博客" 也已经成为了自己(不只是线上) identity 的一部分——毕竟这是很多人认识我的渠道,也重塑了我的一部分自我认知。\n\n虽然期间尝试过《飞书文档初体验》,从国内版本的飞书到 LarkSuite,但终究不如 GitHub + Material for MkDocs 组合来得顺畅。GitHub 也好,飞书也罢,各种五花八门的奇淫巧技和折腾组合,总有能玩出花来的一波人,找到自己喜欢的并持之以恒就已经足够。\n趁着今天有时间,在公众号同步了这一篇,希望我们不忘初心,做到最好。', 'bodyHTML': '

从 2023 年下半年以来 "BioIT爱好者" 这个公众号基本上很少更新了,这一点在《公众号许久没有更新了》就提到过,现在唯一有所区别的是在 GitHub Discussions 的基础上又多了一个个人的独立站点。

\n\n

weiyan-cc-home

\n

weiyan-cc-hblog

\n

全面拥抱 GitHub 的感觉真的很好,加上手机 APP 的加持,更加如虎添翼。回归了最原始 markdown 的编辑和写作,也终于不用再担心在《富文本编辑器与 md 语法的一些困惑》中所顾虑的问题。

\n

从 GitHub 到选择 Material for MkDocs 作为个人博客+文档独立站点,有很多的影响因素,但数据可控算是比较核心的一个出发点。这半年来混迹 GitHub 的确也收获良多,发现了很多有意思的博客和站点,学习到了很多优秀的项目。很多时候阅读别人的博客(站点),总能发现一些好玩的人和事物。

\n

2023 年被椒盐豆豉的一篇《2023 年了你为什么需要写博客》所吸引,尤其是 "博客是赛博空间的另一个你,也能反过来定义你" 这一句,写出了很多心声。

\n
\n

比较反感 "个人品牌" 这个过于商业化的说法,不写技术不写学术的非实名博客甚至起不到简历作用。但它确是比简历更 "像个人",比碎片化社交网络更全面展现我是怎样一个人的网络门面。当然这是我这个博客的用法,网上靠博客经营自己品牌的也比比皆是。总之,内容的自由度和高度的定制化让博客可以成为任何你想让它成为的东西。反之,博客写的久了,发现 "写博客" 也已经成为了自己(不只是线上) identity 的一部分——毕竟这是很多人认识我的渠道,也重塑了我的一部分自我认知。

\n
\n

虽然期间尝试过《飞书文档初体验》,从国内版本的飞书到 LarkSuite,但终究不如 GitHub + Material for MkDocs 组合来得顺畅。GitHub 也好,飞书也罢,各种五花八门的奇淫巧技和折腾组合,总有能玩出花来的一波人,找到自己喜欢的并持之以恒就已经足够。

\n

趁着今天有时间,在公众号同步了这一篇,希望我们不忘初心,做到最好。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': [{'name': '公众号'}]}, 'comments': {'nodes': []}}, {'title': 'Mkdocs material 使用自定义 slug 和 url', 'number': 54, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/54', 'createdAt': '2024-01-23T06:53:45Z', 'lastEditedAt': None, 'updatedAt': '2024-01-23T06:53:46Z', 'body': 'Mkdocs material 默认使用目录+文件名作为 post 展示的 URL,如果目录名/文件名太长的话,你的 URL 就会显得非常长。尤其是当你从浏览器地址栏中复制某一篇文档的链接时候,如果你的 URL 同时包含了中文,URL 转码后会导致你复制后粘贴的链接变得更加长。\r\n\r\n\r\n\r\nMkdocs material 目前我是没看到有什么具体的插件解决这个问题,只不过有人在 [squidfunk/mkdocs-material#5161](https://github.com/squidfunk/mkdocs-material/discussions/5161) 基于 hook 提供了一个解决的方案。这个方案基本上能满足我们的需求,但也有一些限制。\r\n\r\n- slug 必须是不能以 `/` 作为开头,且必须以 `/` 作为结尾。\r\n- 可能会导致内部链接引用出现问题。\r\n- 会重复读取任务,如果文件非常多,会降低相对于文件量的整体性能。', 'bodyText': 'Mkdocs material 默认使用目录+文件名作为 post 展示的 URL,如果目录名/文件名太长的话,你的 URL 就会显得非常长。尤其是当你从浏览器地址栏中复制某一篇文档的链接时候,如果你的 URL 同时包含了中文,URL 转码后会导致你复制后粘贴的链接变得更加长。\n\nMkdocs material 目前我是没看到有什么具体的插件解决这个问题,只不过有人在 squidfunk/mkdocs-material#5161 基于 hook 提供了一个解决的方案。这个方案基本上能满足我们的需求,但也有一些限制。\n\nslug 必须是不能以 / 作为开头,且必须以 / 作为结尾。\n可能会导致内部链接引用出现问题。\n会重复读取任务,如果文件非常多,会降低相对于文件量的整体性能。', 'bodyHTML': '

Mkdocs material 默认使用目录+文件名作为 post 展示的 URL,如果目录名/文件名太长的话,你的 URL 就会显得非常长。尤其是当你从浏览器地址栏中复制某一篇文档的链接时候,如果你的 URL 同时包含了中文,URL 转码后会导致你复制后粘贴的链接变得更加长。

\n\n

Mkdocs material 目前我是没看到有什么具体的插件解决这个问题,只不过有人在 squidfunk/mkdocs-material#5161 基于 hook 提供了一个解决的方案。这个方案基本上能满足我们的需求,但也有一些限制。

\n
    \n
  • slug 必须是不能以 / 作为开头,且必须以 / 作为结尾。
  • \n
  • 可能会导致内部链接引用出现问题。
  • \n
  • 会重复读取任务,如果文件非常多,会降低相对于文件量的整体性能。
  • \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'Mkdocs material 对指定页面隐藏 H1 标题', 'number': 53, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/53', 'createdAt': '2024-01-19T03:42:11Z', 'lastEditedAt': None, 'updatedAt': '2024-01-19T03:42:12Z', 'body': '主要记录一下在 Mkdocs material 中对指定页面隐藏标题,尤其是指在 Home 页面把 H1 级别的标题隐藏的一些解决方法。\r\n\r\n\r\n\r\n## 背景\r\n\r\n对于一些特定的页面,不想显示顶级的标题,尤其是 H1 标题。Mkdocs material 讨论区给出了几个方案:\r\n\r\n1. 内联 CSS 的方法,参考 [squidfunk/mkdocs-material#2163](https://github.com/squidfunk/mkdocs-material/issues/2163)。 \r\n 这个方法的确能解决隐藏当前页面的 H1 标题,但**同时会把搜索栏搜索结果的 H1 标题给隐藏了**。有点治标不治本!\r\n2. 自定义页面模板,参考 [squidfunk/mkdocs-material#6185](https://github.com/squidfunk/mkdocs-material/discussions/6185)。\r\n 这个参考的讨论里面没有给出具体的解决方法,本文章来详细介绍一下。\r\n\r\n## 创建模板\r\n\r\n首先,在 `overrides` 目录下创建一个名为 `home.html` 的文件(文件名可以随意命名),内容可以参考 [`blog.html`](https://github.com/squidfunk/mkdocs-material/blob/master/material/templates/blog.html) 的内容。\r\n```\r\n{% extends "base.html" %}\r\n{% block htmltitle %}\r\n {% if page.meta and page.meta.title %}\r\n {{ page.meta.title }}\r\n {% elif page.title and not page.is_homepage %}\r\n {{ page.title | striptags }}\r\n {% else %}\r\n {{ config.site_name }}\r\n {% endif %}\r\n{% endblock %}\r\n\r\n{% block container %}\r\n
\r\n
\r\n {% block content %}\r\n {% include "partials/mycontent.html" %}\r\n {% endblock %}\r\n
\r\n
\r\n{% endblock %}\r\n\r\n{% block extrahead %}\r\n \r\n \r\n{% endblock %}\r\n```\r\n\r\n第二,创建 `overrides/partials/mycontent.html` 文件,内容参考 [`content.html`](https://github.com/squidfunk/mkdocs-material/blob/master/material/templates/partials/content.html) 文件,注意把 h1 的元素注释掉。\r\n```\r\n{#-\r\n This file was automatically generated - do not edit\r\n-#}\r\n{% if "material/tags" in config.plugins and tags %}\r\n {% include "partials/tags.html" %}\r\n{% endif %}\r\n{% include "partials/actions.html" %}\r\n{% if "\\x3ch1" not in page.content %}\r\n \r\n{% endif %}\r\n{{ page.content }}\r\n{% include "partials/source-file.html" %}\r\n{% include "partials/feedback.html" %}\r\n{% include "partials/comments.html" %}\r\n```\r\n\r\n## 在页面中使用模板\r\n\r\n例如,在个人站点的主页文件 `docs/index.md` 中头部,使用 `template` 指定使用的模板。\r\n```\r\n---\r\ntitle: 维燕的知识花园\r\ntemplate: home.html\r\n---\r\n```\r\n\r\n最后,重新启动 mkdocs 就可以看到对应页面 H1 隐藏后的效果。\r\n', 'bodyText': '主要记录一下在 Mkdocs material 中对指定页面隐藏标题,尤其是指在 Home 页面把 H1 级别的标题隐藏的一些解决方法。\n\n背景\n对于一些特定的页面,不想显示顶级的标题,尤其是 H1 标题。Mkdocs material 讨论区给出了几个方案:\n\n内联 CSS 的方法,参考 squidfunk/mkdocs-material#2163。\n这个方法的确能解决隐藏当前页面的 H1 标题,但同时会把搜索栏搜索结果的 H1 标题给隐藏了。有点治标不治本!\n自定义页面模板,参考 squidfunk/mkdocs-material#6185。\n这个参考的讨论里面没有给出具体的解决方法,本文章来详细介绍一下。\n\n创建模板\n首先,在 overrides 目录下创建一个名为 home.html 的文件(文件名可以随意命名),内容可以参考 blog.html 的内容。\n{% extends "base.html" %}\n{% block htmltitle %}\n {% if page.meta and page.meta.title %}\n {{ page.meta.title }}\n {% elif page.title and not page.is_homepage %}\n {{ page.title | striptags }}\n {% else %}\n {{ config.site_name }}\n {% endif %}\n{% endblock %}\n\n{% block container %}\n
\n
\n {% block content %}\n {% include "partials/mycontent.html" %}\n {% endblock %}\n
\n
\n{% endblock %}\n\n{% block extrahead %}\n \n \n{% endblock %}\n\n第二,创建 overrides/partials/mycontent.html 文件,内容参考 content.html 文件,注意把 h1 的元素注释掉。\n{#-\n This file was automatically generated - do not edit\n-#}\n{% if "material/tags" in config.plugins and tags %}\n {% include "partials/tags.html" %}\n{% endif %}\n{% include "partials/actions.html" %}\n{% if "\\x3ch1" not in page.content %}\n \n{% endif %}\n{{ page.content }}\n{% include "partials/source-file.html" %}\n{% include "partials/feedback.html" %}\n{% include "partials/comments.html" %}\n\n在页面中使用模板\n例如,在个人站点的主页文件 docs/index.md 中头部,使用 template 指定使用的模板。\n---\ntitle: 维燕的知识花园\ntemplate: home.html\n---\n\n最后,重新启动 mkdocs 就可以看到对应页面 H1 隐藏后的效果。', 'bodyHTML': '

主要记录一下在 Mkdocs material 中对指定页面隐藏标题,尤其是指在 Home 页面把 H1 级别的标题隐藏的一些解决方法。

\n\n

背景

\n

对于一些特定的页面,不想显示顶级的标题,尤其是 H1 标题。Mkdocs material 讨论区给出了几个方案:

\n
    \n
  1. 内联 CSS 的方法,参考 squidfunk/mkdocs-material#2163
    \n这个方法的确能解决隐藏当前页面的 H1 标题,但同时会把搜索栏搜索结果的 H1 标题给隐藏了。有点治标不治本!
  2. \n
  3. 自定义页面模板,参考 squidfunk/mkdocs-material#6185
    \n这个参考的讨论里面没有给出具体的解决方法,本文章来详细介绍一下。
  4. \n
\n

创建模板

\n

首先,在 overrides 目录下创建一个名为 home.html 的文件(文件名可以随意命名),内容可以参考 blog.html 的内容。

\n
{% extends "base.html" %}\n{% block htmltitle %}\n      {% if page.meta and page.meta.title %}\n        <title>{{ page.meta.title }}</title>\n      {% elif page.title and not page.is_homepage %}\n        <title>{{ page.title | striptags }}</title>\n      {% else %}\n        <title>{{ config.site_name }}</title>\n      {% endif %}\n{% endblock %}\n\n{% block container %}\n    <div class="md-content" data-md-component="content">\n      <article class="md-content__inner md-typeset">\n        {% block content %}\n          {% include "partials/mycontent.html" %}\n        {% endblock %}\n      </article>\n    </div>\n{% endblock %}\n\n{% block extrahead %}\n      <!--style>.md-typeset h1,.md-content__button {display:none !important}; </style-->\n      <style>.md-header__topic {font-weight:700 !important}</style>\n{% endblock %}\n
\n

第二,创建 overrides/partials/mycontent.html 文件,内容参考 content.html 文件,注意把 h1 的元素注释掉。

\n
{#-\n  This file was automatically generated - do not edit\n-#}\n{% if "material/tags" in config.plugins and tags %}\n  {% include "partials/tags.html" %}\n{% endif %}\n{% include "partials/actions.html" %}\n{% if "\\x3ch1" not in page.content %}\n  <!--h1>{{ page.title | d(config.site_name, true)}}</h1-->\n{% endif %}\n{{ page.content }}\n{% include "partials/source-file.html" %}\n{% include "partials/feedback.html" %}\n{% include "partials/comments.html" %}\n
\n

在页面中使用模板

\n

例如,在个人站点的主页文件 docs/index.md 中头部,使用 template 指定使用的模板。

\n
---\ntitle: 维燕的知识花园\ntemplate: home.html\n---\n
\n

最后,重新启动 mkdocs 就可以看到对应页面 H1 隐藏后的效果。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'MkDocs Material 的一些使用与问题汇总', 'number': 52, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/52', 'createdAt': '2024-01-18T07:51:11Z', 'lastEditedAt': None, 'updatedAt': '2024-01-18T07:51:12Z', 'body': '记录一下 MkDocs Material 在使用过程中遇到的一些问题。\r\n\r\n\r\n\r\n1. 如何避免锚点链接的非英文字符转换成数字 \r\n - [How to disable converting non-english header links to numbers?#4682](https://github.com/squidfunk/mkdocs-material/discussions/4682)', 'bodyText': '记录一下 MkDocs Material 在使用过程中遇到的一些问题。\n\n\n如何避免锚点链接的非英文字符转换成数字\n\nHow to disable converting non-english header links to numbers?#4682', 'bodyHTML': '

记录一下 MkDocs Material 在使用过程中遇到的一些问题。

\n\n
    \n
  1. 如何避免锚点链接的非英文字符转换成数字\n\n
  2. \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'MkDocs 主题 awesome-pages 使用', 'number': 51, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/51', 'createdAt': '2024-01-11T09:24:34Z', 'lastEditedAt': '2024-01-12T02:12:55Z', 'updatedAt': '2024-01-12T02:12:55Z', 'body': '很长一段时间都在使用 [mkdocs_include_dir_to_nav](https://github.com/mysiki/mkdocs_include_dir_to_nav) 这个插件来自动包含目录下的所有 md 文件,但随着新需求的出现 —— **如何给某一个指定的子目录使用 `reverse_sort_file`,即升序排列展示子目录相应的 markdown 内容**。这才开始接触到 [MkDocs Awesome Pages Plugin](https://github.com/lukasgeiter/mkdocs-awesome-pages-plugin) 这个插件。\r\n\r\n\r\n\r\n## 开始\r\n\r\n从 GitHub 可以很直观看到的是 [mkdocs_include_dir_to_nav](https://github.com/mysiki/mkdocs_include_dir_to_nav) 自从 2022-05-01 更新了 [V1.2.0](https://github.com/mysiki/mkdocs_include_dir_to_nav/releases/tag/v1.2.0) 版本后基本就已经停止了更新,Star 也才 20 多人。 \r\n![mkdocs-include-dir-to-nav](https://shub.weiyan.tech/kgarden/2024/01/mkdocs-include-dir-to-nav.png)\r\n\r\n反而是 [MkDocs Awesome Pages Plugin](https://github.com/lukasgeiter/mkdocs-awesome-pages-plugin) 一直保持着非常积极的更新频率,而且维护者和关注和使用用户也远远比 [mkdocs_include_dir_to_nav](https://github.com/mysiki/mkdocs_include_dir_to_nav) 多得多。 \r\n![mkdocs-awesome-pages-plugin](https://shub.weiyan.tech/kgarden/2024/01/mkdocs-awesome-pages-plugin.png)\r\n\r\n于是,开始着入手 [MkDocs Awesome Pages Plugin](https://github.com/lukasgeiter/mkdocs-awesome-pages-plugin)。不得不说,Awesome-Pages 这个插件的功能很强大,可以很好解决我"指定子目录自定义文档排序"的需求。但不可否认的是 Awesome-Pages 的文档写的的确有点糙,不认真看还真不知道应该如何上手,这也是花费我最多时间的地方。\r\n\r\n## 使用\r\n\r\n使用 [MkDocs Awesome Pages Plugin](https://github.com/lukasgeiter/mkdocs-awesome-pages-plugin) 有两个很重要的前提:\r\n\r\n1. 如果你在 `mkdocs.yml` 定义了 `nav` 或 `pages` 条目,则此插件不会执行任何操作。要使用该插件列出的功能,我们必须完全删除该条目或向其中添加 `...` 条目 ([add a `...` entry to it](https://github.com/lukasgeiter/mkdocs-awesome-pages-plugin?tab=readme-ov-file#combine-custom-navigation--file-structure))。\r\n2. 自定义导航时,在目录(或者子目录)中创建一个名为 `.pages` 的文件时,使用 `nav` 属性只能自定义**该级别的导航**!然后,按照文件和子目录在导航中出现的顺序列出文件和子目录。\r\n\r\n```\r\ndocs/\r\n├── README.md\r\n├── dirNamedA\r\n│ ├── dirA-page01.md\r\n│ ├── dirA-page02.md\r\n│ └── subDirNamedA1\r\n│ │ ├── subDirA1-page01.md\r\n│ │ └── subDirA1-page02.md\r\n│ └── subDirNamedA2\r\n│ ├── subDirA2-page01.md\r\n│ └── subDirA2-page02.md\r\n├── dirNamedB\r\n│ ├── dirB-page01.md\r\n│ ├── dirB-page02.md\r\n│ └── subDirNamedB1\r\n│ ├── subDirB1-page01.md\r\n│ └── subDirB1-page02.md\r\n└── emptyDir\r\n```\r\n\r\n这就发现了 [MkDocs Awesome Pages Plugin](https://github.com/lukasgeiter/mkdocs-awesome-pages-plugin) 和 MkDocs 、[mkdocs_include_dir_to_nav](https://github.com/mysiki/mkdocs_include_dir_to_nav) 在设置 navigation 时候的区别:[MkDocs Awesome Pages Plugin](https://github.com/lukasgeiter/mkdocs-awesome-pages-plugin) 的 `nav` 属性只能自定义**该级别的导航**!即无法只通过一个 `.pages` 实现所有目录+子目录的 navigation 排序配置。\r\n\r\n所以,最好的做法就是在 `docs` 目录下(包含 `docs`) 给每个目录增加一个 `.pages` 文件,用于控制当前目录的所有子目录(或者 Posts) 的排序和展示。\r\n\r\n', 'bodyText': '很长一段时间都在使用 mkdocs_include_dir_to_nav 这个插件来自动包含目录下的所有 md 文件,但随着新需求的出现 —— 如何给某一个指定的子目录使用 reverse_sort_file,即升序排列展示子目录相应的 markdown 内容。这才开始接触到 MkDocs Awesome Pages Plugin 这个插件。\n\n开始\n从 GitHub 可以很直观看到的是 mkdocs_include_dir_to_nav 自从 2022-05-01 更新了 V1.2.0 版本后基本就已经停止了更新,Star 也才 20 多人。\n\n反而是 MkDocs Awesome Pages Plugin 一直保持着非常积极的更新频率,而且维护者和关注和使用用户也远远比 mkdocs_include_dir_to_nav 多得多。\n\n于是,开始着入手 MkDocs Awesome Pages Plugin。不得不说,Awesome-Pages 这个插件的功能很强大,可以很好解决我"指定子目录自定义文档排序"的需求。但不可否认的是 Awesome-Pages 的文档写的的确有点糙,不认真看还真不知道应该如何上手,这也是花费我最多时间的地方。\n使用\n使用 MkDocs Awesome Pages Plugin 有两个很重要的前提:\n\n如果你在 mkdocs.yml 定义了 nav 或 pages 条目,则此插件不会执行任何操作。要使用该插件列出的功能,我们必须完全删除该条目或向其中添加 ... 条目 (add a ... entry to it)。\n自定义导航时,在目录(或者子目录)中创建一个名为 .pages 的文件时,使用 nav 属性只能自定义该级别的导航!然后,按照文件和子目录在导航中出现的顺序列出文件和子目录。\n\ndocs/\n├── README.md\n├── dirNamedA\n│ ├── dirA-page01.md\n│ ├── dirA-page02.md\n│ └── subDirNamedA1\n│ │ ├── subDirA1-page01.md\n│ │ └── subDirA1-page02.md\n│ └── subDirNamedA2\n│ ├── subDirA2-page01.md\n│ └── subDirA2-page02.md\n├── dirNamedB\n│ ├── dirB-page01.md\n│ ├── dirB-page02.md\n│ └── subDirNamedB1\n│ ├── subDirB1-page01.md\n│ └── subDirB1-page02.md\n└── emptyDir\n\n这就发现了 MkDocs Awesome Pages Plugin 和 MkDocs 、mkdocs_include_dir_to_nav 在设置 navigation 时候的区别:MkDocs Awesome Pages Plugin 的 nav 属性只能自定义该级别的导航!即无法只通过一个 .pages 实现所有目录+子目录的 navigation 排序配置。\n所以,最好的做法就是在 docs 目录下(包含 docs) 给每个目录增加一个 .pages 文件,用于控制当前目录的所有子目录(或者 Posts) 的排序和展示。', 'bodyHTML': '

很长一段时间都在使用 mkdocs_include_dir_to_nav 这个插件来自动包含目录下的所有 md 文件,但随着新需求的出现 —— 如何给某一个指定的子目录使用 reverse_sort_file,即升序排列展示子目录相应的 markdown 内容。这才开始接触到 MkDocs Awesome Pages Plugin 这个插件。

\n\n

开始

\n

从 GitHub 可以很直观看到的是 mkdocs_include_dir_to_nav 自从 2022-05-01 更新了 V1.2.0 版本后基本就已经停止了更新,Star 也才 20 多人。
\nmkdocs-include-dir-to-nav

\n

反而是 MkDocs Awesome Pages Plugin 一直保持着非常积极的更新频率,而且维护者和关注和使用用户也远远比 mkdocs_include_dir_to_nav 多得多。
\nmkdocs-awesome-pages-plugin

\n

于是,开始着入手 MkDocs Awesome Pages Plugin。不得不说,Awesome-Pages 这个插件的功能很强大,可以很好解决我"指定子目录自定义文档排序"的需求。但不可否认的是 Awesome-Pages 的文档写的的确有点糙,不认真看还真不知道应该如何上手,这也是花费我最多时间的地方。

\n

使用

\n

使用 MkDocs Awesome Pages Plugin 有两个很重要的前提:

\n
    \n
  1. 如果你在 mkdocs.yml 定义了 navpages 条目,则此插件不会执行任何操作。要使用该插件列出的功能,我们必须完全删除该条目或向其中添加 ... 条目 (add a ... entry to it)。
  2. \n
  3. 自定义导航时,在目录(或者子目录)中创建一个名为 .pages 的文件时,使用 nav 属性只能自定义该级别的导航!然后,按照文件和子目录在导航中出现的顺序列出文件和子目录。
  4. \n
\n
docs/\n├── README.md\n├── dirNamedA\n│   ├── dirA-page01.md\n│   ├── dirA-page02.md\n│   └── subDirNamedA1\n│   │   ├── subDirA1-page01.md\n│   │   └── subDirA1-page02.md\n│   └── subDirNamedA2\n│       ├── subDirA2-page01.md\n│       └── subDirA2-page02.md\n├── dirNamedB\n│   ├── dirB-page01.md\n│   ├── dirB-page02.md\n│   └── subDirNamedB1\n│       ├── subDirB1-page01.md\n│       └── subDirB1-page02.md\n└── emptyDir\n
\n

这就发现了 MkDocs Awesome Pages Plugin 和 MkDocs 、mkdocs_include_dir_to_nav 在设置 navigation 时候的区别:MkDocs Awesome Pages Pluginnav 属性只能自定义该级别的导航!即无法只通过一个 .pages 实现所有目录+子目录的 navigation 排序配置。

\n

所以,最好的做法就是在 docs 目录下(包含 docs) 给每个目录增加一个 .pages 文件,用于控制当前目录的所有子目录(或者 Posts) 的排序和展示。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '2023 年年终总结', 'number': 50, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/50', 'createdAt': '2024-01-10T05:34:20Z', 'lastEditedAt': '2024-01-10T09:10:58Z', 'updatedAt': '2024-01-10T09:10:58Z', 'body': '本来没想着写年终总结 —— 主要是最近对于码字没太多的欲望,但翻到了 2021/2022 的一些年终记录,也看了不少其他网友博主 2023 年的总结,所以对自己说,还是写一写吧。\r\n\r\n2023 年对个人来说是变动的一年,这个变动主要体现在工作上。反观生活,除去家庭的一些琐事基本上也就是波澜不惊的一个状态。\r\n\r\n\r\n\r\n## 工作\r\n\r\n2023 年工作最大的变动之一就是公司搬迁新的厂区。随之而来是上下班通勤的变更,这一切让原本相对充裕的时间变得更加紧凑。但时间是最大的习惯,久而久之这就成了生活的一部分,朝九晚五体现的淋漓尽致。\r\n\r\n第二个变动最大的是新办公地点新办公规章。这一点影响很大,以至于让我不得不放弃了很多以前形成的一部分工具习惯,转身去重新接纳一些新的工具和平台。于是,有了现在的[个人知识站点](https://weiyan.cc),有了[飞书的使用体验](https://www.weiyan.cc/blog/2023/10/24/discussion-11/),GitHub 更是一瞬间成为了个人最常逛和依赖的平台 —— 这也让我重新认识了这个平台的强大和无可替代。 \r\n

\r\n github-contributions-2023\r\n

\r\n\r\n职业方向上探索了一把 AI,浅尝辄止又摸不着门道;mRNA 到 Protein 的优化道路上才刚刚看到入口,任重道远;只能背靠着老本行,在不断优化的道路上踉踉跄跄走着。\r\n\r\n职业生涯的道路上人来人往,铁打的营盘流水的兵,走了就走了,无需留念。\r\n\r\n## 生活\r\n\r\n生活上其实没什么太多说的,感觉到微妙变化的是比以前更加注意到自己和身边人的健康问题了。从老婆孩子,到母亲的腰椎问题,再到自己,再加上这一年的流感、肺炎(尤其是支原体肺炎),2023 年在健康这个问题上的确投入了很大的一部分时间和精力。\r\n\r\n家庭琐事上,家人彼此磕磕碰碰的事情总会有,生活无律,人生无常,我们更需要的是相互之间相互理解与包容。对于老婆和孩子,需要更多的关心和陪伴。\r\n\r\n运动这件事情上,基本还能保持着每周至少一场羽毛球,这是值得肯定的。虽然变换了新的地方,融入了新的面孔,但至少我们还能在一起用羽毛球找到属于彼此的快乐,那也足够了。\r\n\r\n孩子的事情上,这一年约着她的同班同学打卡了不少地方,这也让集体一起遛娃成为了周末值得期待的活动之一。\r\n\r\n## 最后\r\n\r\n最后,2024 年就要搬进新的房子了,这是值得期待和努力的一件大事。希望自己和家人在新的环境中能收获新的惊喜,身体健康,和和美满。\r\n\r\n', 'bodyText': '本来没想着写年终总结 —— 主要是最近对于码字没太多的欲望,但翻到了 2021/2022 的一些年终记录,也看了不少其他网友博主 2023 年的总结,所以对自己说,还是写一写吧。\n2023 年对个人来说是变动的一年,这个变动主要体现在工作上。反观生活,除去家庭的一些琐事基本上也就是波澜不惊的一个状态。\n\n工作\n2023 年工作最大的变动之一就是公司搬迁新的厂区。随之而来是上下班通勤的变更,这一切让原本相对充裕的时间变得更加紧凑。但时间是最大的习惯,久而久之这就成了生活的一部分,朝九晚五体现的淋漓尽致。\n第二个变动最大的是新办公地点新办公规章。这一点影响很大,以至于让我不得不放弃了很多以前形成的一部分工具习惯,转身去重新接纳一些新的工具和平台。于是,有了现在的个人知识站点,有了飞书的使用体验,GitHub 更是一瞬间成为了个人最常逛和依赖的平台 —— 这也让我重新认识了这个平台的强大和无可替代。\n\n \n\n职业方向上探索了一把 AI,浅尝辄止又摸不着门道;mRNA 到 Protein 的优化道路上才刚刚看到入口,任重道远;只能背靠着老本行,在不断优化的道路上踉踉跄跄走着。\n职业生涯的道路上人来人往,铁打的营盘流水的兵,走了就走了,无需留念。\n生活\n生活上其实没什么太多说的,感觉到微妙变化的是比以前更加注意到自己和身边人的健康问题了。从老婆孩子,到母亲的腰椎问题,再到自己,再加上这一年的流感、肺炎(尤其是支原体肺炎),2023 年在健康这个问题上的确投入了很大的一部分时间和精力。\n家庭琐事上,家人彼此磕磕碰碰的事情总会有,生活无律,人生无常,我们更需要的是相互之间相互理解与包容。对于老婆和孩子,需要更多的关心和陪伴。\n运动这件事情上,基本还能保持着每周至少一场羽毛球,这是值得肯定的。虽然变换了新的地方,融入了新的面孔,但至少我们还能在一起用羽毛球找到属于彼此的快乐,那也足够了。\n孩子的事情上,这一年约着她的同班同学打卡了不少地方,这也让集体一起遛娃成为了周末值得期待的活动之一。\n最后\n最后,2024 年就要搬进新的房子了,这是值得期待和努力的一件大事。希望自己和家人在新的环境中能收获新的惊喜,身体健康,和和美满。', 'bodyHTML': '

本来没想着写年终总结 —— 主要是最近对于码字没太多的欲望,但翻到了 2021/2022 的一些年终记录,也看了不少其他网友博主 2023 年的总结,所以对自己说,还是写一写吧。

\n

2023 年对个人来说是变动的一年,这个变动主要体现在工作上。反观生活,除去家庭的一些琐事基本上也就是波澜不惊的一个状态。

\n\n

工作

\n

2023 年工作最大的变动之一就是公司搬迁新的厂区。随之而来是上下班通勤的变更,这一切让原本相对充裕的时间变得更加紧凑。但时间是最大的习惯,久而久之这就成了生活的一部分,朝九晚五体现的淋漓尽致。

\n

第二个变动最大的是新办公地点新办公规章。这一点影响很大,以至于让我不得不放弃了很多以前形成的一部分工具习惯,转身去重新接纳一些新的工具和平台。于是,有了现在的个人知识站点,有了飞书的使用体验,GitHub 更是一瞬间成为了个人最常逛和依赖的平台 —— 这也让我重新认识了这个平台的强大和无可替代。

\n

\n github-contributions-2023\n

\n

职业方向上探索了一把 AI,浅尝辄止又摸不着门道;mRNA 到 Protein 的优化道路上才刚刚看到入口,任重道远;只能背靠着老本行,在不断优化的道路上踉踉跄跄走着。

\n

职业生涯的道路上人来人往,铁打的营盘流水的兵,走了就走了,无需留念。

\n

生活

\n

生活上其实没什么太多说的,感觉到微妙变化的是比以前更加注意到自己和身边人的健康问题了。从老婆孩子,到母亲的腰椎问题,再到自己,再加上这一年的流感、肺炎(尤其是支原体肺炎),2023 年在健康这个问题上的确投入了很大的一部分时间和精力。

\n

家庭琐事上,家人彼此磕磕碰碰的事情总会有,生活无律,人生无常,我们更需要的是相互之间相互理解与包容。对于老婆和孩子,需要更多的关心和陪伴。

\n

运动这件事情上,基本还能保持着每周至少一场羽毛球,这是值得肯定的。虽然变换了新的地方,融入了新的面孔,但至少我们还能在一起用羽毛球找到属于彼此的快乐,那也足够了。

\n

孩子的事情上,这一年约着她的同班同学打卡了不少地方,这也让集体一起遛娃成为了周末值得期待的活动之一。

\n

最后

\n

最后,2024 年就要搬进新的房子了,这是值得期待和努力的一件大事。希望自己和家人在新的环境中能收获新的惊喜,身体健康,和和美满。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '苹果字体 PingFang SC 的一些踩坑记录', 'number': 49, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/49', 'createdAt': '2024-01-09T05:43:52Z', 'lastEditedAt': '2024-06-03T07:43:27Z', 'updatedAt': '2024-06-03T07:43:27Z', 'body': '曾经在 《[为 Windows 系统替换优雅的苹果字体](https://www.weiyan.cc/cookbook/%E5%BC%80%E5%8F%91%E8%BF%90%E7%BB%B4/windows/2021-02-19-win-font/)》中提到可在 Windows 中使用苹方字体替代默认的微软雅黑,这里就有一个问题即需要在 Wondows 下安装苹方字体 —— 如果你的字体安装错误,很有可能导致你的浏览器或其他应用出现乱码。\r\n\r\n## 浏览器乱码\r\n\r\n出现这个的原因主要是站点使用了 `PingFang SC` 的字体设置。\r\n```\r\nbody {\r\n font-family: PingFang SC,microsoft yahei,sans-serif;\r\n}\r\n```\r\n\r\n我们可以看到使用 F12 检查源码模式把 `font-family` 中的 `PingFang SC` 去掉后即可显示正常。\r\n\r\n## 字体安装后不起作用\r\n\r\n这里就涉及一个 **萍方** vs **苹方** vs **PingFang** 区别的一个问题。\r\n\r\n> 猛地看上去,萍方/苹方/PingFang 应该是同一个字体。但是,实际上的效果,却并不相同。那么,到底谁是真正的 pingfang sc呢? \r\n> \r\n> 这里以能否**以 PingFang SC 为名称识别出来,作为标准**。为什么这么说呢?因为网页里面的 font-family,写的都是 pingfang sc,也许萍方/苹方都是差不多的字体,但是不能在网页里面自动识别出来。所以,就等于零。\r\n> \r\n> ```\r\n> body {\r\n> font-family: PingFang SC,microsoft yahei,sans-serif;\r\n> }\r\n> ```\r\n> 比如,上述 css 定义,就来自于腾讯云主页。在实际的应用过程中,只有安装好的 pingfang sc 系列字体才能被识别【如下图中的右侧字体】。 \r\n> **注意:萍方/苹方,在安装的时候,文件名也都是 pingfang-sc 之类的文件名。但是,安装完成的真正成品,可不是这个拼音名字。进而导致字体不能识别。**\r\n> ![pingfang sc 区别](https://shub.weiyan.tech/kgarden/2024/01/fingfang-sc.png)\r\n> \r\n> From 《[由 pingfang sc 字体缺失,所暴露的字体加载顺序的潜规则](https://newsn.net/say/css-font-family-pingfang.html)》\r\n\r\n## 解决方案\r\n\r\n参考 《[由 pingfang sc 字体缺失,所暴露的字体加载顺序的潜规则](https://newsn.net/say/css-font-family-pingfang.html)》 一文的方案。\r\n\r\n### 安装 PingFang SC\r\n\r\n名称为 **PingFang SC** (英文) 的字体找了很久才在 GitHub 翻到一个(以防丢失,个人 Fork 了过来):[shenweiyan/PingFangSC-Fonts](https://github.com/shenweiyan/PingFangSC-Fonts),如有需要可以直接下载安装。\r\n\r\n> 国内大多数网页,在定义网页字体的时候,都是先定义 PingFang SC,然后定义微软雅黑。那么: \r\n> \r\n> - 正常来说,win 系统是不会安装 PingFang SC 字体的,所以,显示微软雅黑,页面正常。 \r\n> - 但是,一旦单独安装了 PingFang SC Light,页面就会识别出这个 Light 字体,页面不正常。 \r\n> - 解决方案是:再安装一个 PingFang SC Regular,页面会在 Light 之前优先识别 Regular,页面正常。 \r\n\r\n> \r\n> 如果您非要在 win 下面安装 pingfang sc 字体,可能要三思而后安装了。李鬼似乎有点多...\r\n\r\n> \r\n> ![PingFang SC Regular](https://shub.weiyan.tech/kgarden/2024/01/pingfang-sc-regular.png)\r\n\r\n### 删除 PingFang SC\r\n\r\n个人用的就是这一个方法,但是在 `C:\\Windows\\Fonts` 中删除的时候会提示 **该字体正在使用无法删除!所以,必须要关闭使用苹方字体的程序。**\r\n\r\n因此,我们需要:\r\n\r\n参考:《[电脑安装新字体,浏览器字体全变了,如何删除正在使用的苹方字体](https://www.bilibili.com/video/BV1nc411575s/)》 - 哔哩哔哩\r\n\r\n- 在 Windows 任务管理的进程中把浏览器相关的全部结束掉,如 360 浏览器相关的进程、Microsoft edge、Google Chrome 等等,全部选择结束任务。 \r\n- 把其他可能使用苹方字体的,如 OneNote、WPS、微信、... 这些的进程也全部结束掉。 \r\n\r\n最后,回到 `C:\\Windows\\Fonts` 中再次删除相应的苹方字体,发现即可成功删除。删除了这些苹方字体,浏览器上的字体显示也就恢复正常了。\r\n\r\n## 参考资料\r\n\r\n1. 苏南大叔,《[由 pingfang sc 字体缺失,所暴露的字体加载顺序的潜规则](https://newsn.net/say/css-font-family-pingfang.html)》\r\n2. 科技猎手2023,《[电脑安装新字体,浏览器字体全变了,如何删除正在使用的苹方字体](https://www.bilibili.com/video/BV1nc411575s/)》 - 哔哩哔哩', 'bodyText': '曾经在 《为 Windows 系统替换优雅的苹果字体》中提到可在 Windows 中使用苹方字体替代默认的微软雅黑,这里就有一个问题即需要在 Wondows 下安装苹方字体 —— 如果你的字体安装错误,很有可能导致你的浏览器或其他应用出现乱码。\n浏览器乱码\n出现这个的原因主要是站点使用了 PingFang SC 的字体设置。\nbody {\n font-family: PingFang SC,microsoft yahei,sans-serif;\n}\n\n我们可以看到使用 F12 检查源码模式把 font-family 中的 PingFang SC 去掉后即可显示正常。\n字体安装后不起作用\n这里就涉及一个 萍方 vs 苹方 vs PingFang 区别的一个问题。\n\n猛地看上去,萍方/苹方/PingFang 应该是同一个字体。但是,实际上的效果,却并不相同。那么,到底谁是真正的 pingfang sc呢?\n这里以能否以 PingFang SC 为名称识别出来,作为标准。为什么这么说呢?因为网页里面的 font-family,写的都是 pingfang sc,也许萍方/苹方都是差不多的字体,但是不能在网页里面自动识别出来。所以,就等于零。\nbody {\n font-family: PingFang SC,microsoft yahei,sans-serif;\n}\n\n比如,上述 css 定义,就来自于腾讯云主页。在实际的应用过程中,只有安装好的 pingfang sc 系列字体才能被识别【如下图中的右侧字体】。\n注意:萍方/苹方,在安装的时候,文件名也都是 pingfang-sc 之类的文件名。但是,安装完成的真正成品,可不是这个拼音名字。进而导致字体不能识别。\n\nFrom 《由 pingfang sc 字体缺失,所暴露的字体加载顺序的潜规则》\n\n解决方案\n参考 《由 pingfang sc 字体缺失,所暴露的字体加载顺序的潜规则》 一文的方案。\n安装 PingFang SC\n名称为 PingFang SC (英文) 的字体找了很久才在 GitHub 翻到一个(以防丢失,个人 Fork 了过来):shenweiyan/PingFangSC-Fonts,如有需要可以直接下载安装。\n\n国内大多数网页,在定义网页字体的时候,都是先定义 PingFang SC,然后定义微软雅黑。那么:\n\n正常来说,win 系统是不会安装 PingFang SC 字体的,所以,显示微软雅黑,页面正常。\n但是,一旦单独安装了 PingFang SC Light,页面就会识别出这个 Light 字体,页面不正常。\n解决方案是:再安装一个 PingFang SC Regular,页面会在 Light 之前优先识别 Regular,页面正常。\n\n\n\n如果您非要在 win 下面安装 pingfang sc 字体,可能要三思而后安装了。李鬼似乎有点多...\n\n\n\n\n删除 PingFang SC\n个人用的就是这一个方法,但是在 C:\\Windows\\Fonts 中删除的时候会提示 该字体正在使用无法删除!所以,必须要关闭使用苹方字体的程序。\n因此,我们需要:\n参考:《电脑安装新字体,浏览器字体全变了,如何删除正在使用的苹方字体》 - 哔哩哔哩\n\n在 Windows 任务管理的进程中把浏览器相关的全部结束掉,如 360 浏览器相关的进程、Microsoft edge、Google Chrome 等等,全部选择结束任务。\n把其他可能使用苹方字体的,如 OneNote、WPS、微信、... 这些的进程也全部结束掉。\n\n最后,回到 C:\\Windows\\Fonts 中再次删除相应的苹方字体,发现即可成功删除。删除了这些苹方字体,浏览器上的字体显示也就恢复正常了。\n参考资料\n\n苏南大叔,《由 pingfang sc 字体缺失,所暴露的字体加载顺序的潜规则》\n科技猎手2023,《电脑安装新字体,浏览器字体全变了,如何删除正在使用的苹方字体》 - 哔哩哔哩', 'bodyHTML': '

曾经在 《为 Windows 系统替换优雅的苹果字体》中提到可在 Windows 中使用苹方字体替代默认的微软雅黑,这里就有一个问题即需要在 Wondows 下安装苹方字体 —— 如果你的字体安装错误,很有可能导致你的浏览器或其他应用出现乱码。

\n

浏览器乱码

\n

出现这个的原因主要是站点使用了 PingFang SC 的字体设置。

\n
body {\n    font-family: PingFang SC,microsoft yahei,sans-serif;\n}\n
\n

我们可以看到使用 F12 检查源码模式把 font-family 中的 PingFang SC 去掉后即可显示正常。

\n

字体安装后不起作用

\n

这里就涉及一个 萍方 vs 苹方 vs PingFang 区别的一个问题。

\n
\n

猛地看上去,萍方/苹方/PingFang 应该是同一个字体。但是,实际上的效果,却并不相同。那么,到底谁是真正的 pingfang sc呢?

\n

这里以能否以 PingFang SC 为名称识别出来,作为标准。为什么这么说呢?因为网页里面的 font-family,写的都是 pingfang sc,也许萍方/苹方都是差不多的字体,但是不能在网页里面自动识别出来。所以,就等于零。

\n
body {\n   font-family: PingFang SC,microsoft yahei,sans-serif;\n}\n
\n

比如,上述 css 定义,就来自于腾讯云主页。在实际的应用过程中,只有安装好的 pingfang sc 系列字体才能被识别【如下图中的右侧字体】。
\n注意:萍方/苹方,在安装的时候,文件名也都是 pingfang-sc 之类的文件名。但是,安装完成的真正成品,可不是这个拼音名字。进而导致字体不能识别。
\npingfang sc 区别

\n

From 《由 pingfang sc 字体缺失,所暴露的字体加载顺序的潜规则

\n
\n

解决方案

\n

参考 《由 pingfang sc 字体缺失,所暴露的字体加载顺序的潜规则》 一文的方案。

\n

安装 PingFang SC

\n

名称为 PingFang SC (英文) 的字体找了很久才在 GitHub 翻到一个(以防丢失,个人 Fork 了过来):shenweiyan/PingFangSC-Fonts,如有需要可以直接下载安装。

\n
\n

国内大多数网页,在定义网页字体的时候,都是先定义 PingFang SC,然后定义微软雅黑。那么:

\n
    \n
  • 正常来说,win 系统是不会安装 PingFang SC 字体的,所以,显示微软雅黑,页面正常。
  • \n
  • 但是,一旦单独安装了 PingFang SC Light,页面就会识别出这个 Light 字体,页面不正常。
  • \n
  • 解决方案是:再安装一个 PingFang SC Regular,页面会在 Light 之前优先识别 Regular,页面正常。
  • \n
\n
\n
\n

如果您非要在 win 下面安装 pingfang sc 字体,可能要三思而后安装了。李鬼似乎有点多...

\n
\n
\n

PingFang SC Regular

\n
\n

删除 PingFang SC

\n

个人用的就是这一个方法,但是在 C:\\Windows\\Fonts 中删除的时候会提示 该字体正在使用无法删除!所以,必须要关闭使用苹方字体的程序。

\n

因此,我们需要:

\n

参考:《电脑安装新字体,浏览器字体全变了,如何删除正在使用的苹方字体》 - 哔哩哔哩

\n
    \n
  • 在 Windows 任务管理的进程中把浏览器相关的全部结束掉,如 360 浏览器相关的进程、Microsoft edge、Google Chrome 等等,全部选择结束任务。
  • \n
  • 把其他可能使用苹方字体的,如 OneNote、WPS、微信、... 这些的进程也全部结束掉。
  • \n
\n

最后,回到 C:\\Windows\\Fonts 中再次删除相应的苹方字体,发现即可成功删除。删除了这些苹方字体,浏览器上的字体显示也就恢复正常了。

\n

参考资料

\n
    \n
  1. 苏南大叔,《由 pingfang sc 字体缺失,所暴露的字体加载顺序的潜规则
  2. \n
  3. 科技猎手2023,《电脑安装新字体,浏览器字体全变了,如何删除正在使用的苹方字体》 - 哔哩哔哩
  4. \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '公众号'}, {'name': '1.3.10-Windows'}]}, 'comments': {'nodes': []}}, {'title': '2-框架依赖', 'number': 48, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/48', 'createdAt': '2024-01-08T03:49:03Z', 'lastEditedAt': '2024-01-12T07:11:22Z', 'updatedAt': '2024-04-24T06:54:28Z', 'body': '> 编译:[Shen Weiyan](https://www.weiyan.cc) \r\n> 原文: ', 'bodyText': '编译:Shen Weiyan\n原文:https://docs.galaxyproject.org/en/master/admin/python.html', 'bodyHTML': '
\n

编译:Shen Weiyan
\n原文:https://docs.galaxyproject.org/en/master/admin/python.html

\n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '3.1-Galaxy'}, 'labels': {'nodes': [{'name': '3.1.2-Administration'}]}, 'comments': {'nodes': []}}, {'title': '1-支持的 Python 版本', 'number': 47, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/47', 'createdAt': '2024-01-08T02:21:30Z', 'lastEditedAt': '2024-01-12T07:11:40Z', 'updatedAt': '2024-04-24T06:54:09Z', 'body': '> 编译:[沈维燕](https://www.weiyan.cc) \r\n> 原文: \r\n\r\nGalaxy 的核心功能目前支持 Python >=3.7。\r\n\r\n如果 Galaxy 排斥你正在使用的 Python 版本:\r\n\r\n1. 完全删除 Galaxy 使用的 Python virtualenv(可以使用 `GALAXY_VIRTUAL_ENV` 环境变量配置,默认为 `.venv` ),例如: `rm -rf /path/to/galaxy/.venv`。\r\n2. 如果您在 conda 环境中使用 Python(可以使用 `GALAXY_CONDA_ENV` 环境变量进行配置,默认为 `_galaxy_`),请将其删除,例如: `conda env remove -n _galaxy_`。\r\n3. 让 Galaxy 知道要使用哪个 Python 的方法有以下几种: \r\n - 如果您想从 conda 使用 Python,只需激活 `base` 环境,Galaxy 将为自己创建一个新的 conda 环境。\r\n - 否则: \r\n - 确保安装了受支持的 Python 版本。\r\n - 验证您要使用的 Python 解释器是否位于 `which -a python3 python` 输出中的第一个位置(如果您使用的是 Galaxy <=19.09,则为 `which -a python` )。如果不是这种情况: \r\n - 如果您使用的是 Galaxy >= 20.01,只需执行: `export GALAXY_PYTHON=/path/to/python`。\r\n - 如果你使用的是较旧版本的 Galaxy,你可以操控你的 shell 的 `PATH` 变量,将正确的版本置于首位。你可以通过创建一个新目录,将 python 的符号链接添加到其中,并将该目录置于 PATH 的最前面来完成此操作:\r\n ```bash\r\n % mkdir ~/galaxy-python\r\n % ln -s /path/to/python ~/galaxy-python/python\r\n % export PATH=~/galaxy-python:$PATH\r\n ```\r\n\r\n4. 从 Python 2 升级时,删除已编译的 `mako` 模板:\r\n ```basn\r\n % rm -rf /path/to/galaxy/database/compiled_templates/\r\n ```\r\n 这些模板将在启动 Galaxy 时自动重新生成。\r\n\r\n5. 再次启动 Galaxy。\r\n\r\n!!! abstract "注意"\r\n\r\n 如果您从源代码编译自己的 Python 解释器,请确保构建了 `ssl`、`sqlite3`、`curses` 和 `bz2` 模块,并且安装后可导入。这些 "额外" 模块是在编译过程的最后阶段构建的,并且是 Galaxy 框架所需的。如果在 Linux 上进行编译,您可能需要安装适用于 OpenSSL 和 Bzip2 的 `-dev` 包。您可能还需要使用共享库 (`--enable-shared`) 构建 Python。', 'bodyText': '编译:沈维燕\n原文:https://docs.galaxyproject.org/en/master/admin/python.html\n\nGalaxy 的核心功能目前支持 Python >=3.7。\n如果 Galaxy 排斥你正在使用的 Python 版本:\n\n\n完全删除 Galaxy 使用的 Python virtualenv(可以使用 GALAXY_VIRTUAL_ENV 环境变量配置,默认为 .venv ),例如: rm -rf /path/to/galaxy/.venv。\n\n\n如果您在 conda 环境中使用 Python(可以使用 GALAXY_CONDA_ENV 环境变量进行配置,默认为 _galaxy_),请将其删除,例如: conda env remove -n _galaxy_。\n\n\n让 Galaxy 知道要使用哪个 Python 的方法有以下几种:\n\n如果您想从 conda 使用 Python,只需激活 base 环境,Galaxy 将为自己创建一个新的 conda 环境。\n否则:\n\n确保安装了受支持的 Python 版本。\n验证您要使用的 Python 解释器是否位于 which -a python3 python 输出中的第一个位置(如果您使用的是 Galaxy <=19.09,则为 which -a python )。如果不是这种情况:\n\n如果您使用的是 Galaxy >= 20.01,只需执行: export GALAXY_PYTHON=/path/to/python。\n如果你使用的是较旧版本的 Galaxy,你可以操控你的 shell 的 PATH 变量,将正确的版本置于首位。你可以通过创建一个新目录,将 python 的符号链接添加到其中,并将该目录置于 PATH 的最前面来完成此操作:\n% mkdir ~/galaxy-python\n% ln -s /path/to/python ~/galaxy-python/python\n% export PATH=~/galaxy-python:$PATH\n\n\n\n\n\n\n\n\n从 Python 2 升级时,删除已编译的 mako 模板:\n% rm -rf /path/to/galaxy/database/compiled_templates/\n\n这些模板将在启动 Galaxy 时自动重新生成。\n\n\n再次启动 Galaxy。\n\n\n!!! abstract "注意"\n如果您从源代码编译自己的 Python 解释器,请确保构建了 `ssl`、`sqlite3`、`curses` 和 `bz2` 模块,并且安装后可导入。这些 "额外" 模块是在编译过程的最后阶段构建的,并且是 Galaxy 框架所需的。如果在 Linux 上进行编译,您可能需要安装适用于 OpenSSL 和 Bzip2 的 `-dev` 包。您可能还需要使用共享库 (`--enable-shared`) 构建 Python。', 'bodyHTML': '
\n

编译:沈维燕
\n原文:https://docs.galaxyproject.org/en/master/admin/python.html

\n
\n

Galaxy 的核心功能目前支持 Python >=3.7。

\n

如果 Galaxy 排斥你正在使用的 Python 版本:

\n
    \n
  1. \n

    完全删除 Galaxy 使用的 Python virtualenv(可以使用 GALAXY_VIRTUAL_ENV 环境变量配置,默认为 .venv ),例如: rm -rf /path/to/galaxy/.venv

    \n
  2. \n
  3. \n

    如果您在 conda 环境中使用 Python(可以使用 GALAXY_CONDA_ENV 环境变量进行配置,默认为 _galaxy_),请将其删除,例如: conda env remove -n _galaxy_

    \n
  4. \n
  5. \n

    让 Galaxy 知道要使用哪个 Python 的方法有以下几种:

    \n
      \n
    • 如果您想从 conda 使用 Python,只需激活 base 环境,Galaxy 将为自己创建一个新的 conda 环境。
    • \n
    • 否则:\n
        \n
      • 确保安装了受支持的 Python 版本。
      • \n
      • 验证您要使用的 Python 解释器是否位于 which -a python3 python 输出中的第一个位置(如果您使用的是 Galaxy <=19.09,则为 which -a python )。如果不是这种情况:\n
          \n
        • 如果您使用的是 Galaxy >= 20.01,只需执行: export GALAXY_PYTHON=/path/to/python
        • \n
        • 如果你使用的是较旧版本的 Galaxy,你可以操控你的 shell 的 PATH 变量,将正确的版本置于首位。你可以通过创建一个新目录,将 python 的符号链接添加到其中,并将该目录置于 PATH 的最前面来完成此操作:\n
          % mkdir ~/galaxy-python\n% ln -s /path/to/python ~/galaxy-python/python\n% export PATH=~/galaxy-python:$PATH
          \n
        • \n
        \n
      • \n
      \n
    • \n
    \n
  6. \n
  7. \n

    从 Python 2 升级时,删除已编译的 mako 模板:

    \n
    % rm -rf /path/to/galaxy/database/compiled_templates/\n
    \n

    这些模板将在启动 Galaxy 时自动重新生成。

    \n
  8. \n
  9. \n

    再次启动 Galaxy。

    \n
  10. \n
\n

!!! abstract "注意"

\n
如果您从源代码编译自己的 Python 解释器,请确保构建了 `ssl`、`sqlite3`、`curses` 和 `bz2` 模块,并且安装后可导入。这些 "额外" 模块是在编译过程的最后阶段构建的,并且是 Galaxy 框架所需的。如果在 Linux 上进行编译,您可能需要安装适用于 OpenSSL 和 Bzip2 的 `-dev` 包。您可能还需要使用共享库 (`--enable-shared`) 构建 Python。\n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '3.1-Galaxy'}, 'labels': {'nodes': [{'name': '3.1.2-Administration'}]}, 'comments': {'nodes': []}}, {'title': 'Galaxy Project 的 Sphinx 文档部署', 'number': 46, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/46', 'createdAt': '2024-01-05T07:29:59Z', 'lastEditedAt': '2024-02-02T01:23:29Z', 'updatedAt': '2024-04-24T06:29:53Z', 'body': ' 是 Galaxy Project 官方的文档地址链接,这是一个基于 [Sphinx](https://www.sphinx-doc.org/) + [Read the Docs](https://readthedocs.org/) 的文档站点。如果我们也想要创建一个这样一模一样的 Galaxy 文档需要怎么操作呢?\r\n\r\n\r\n\r\n虽然 [Galaxy 官方文档](https://docs.galaxyproject.org/en/master/#building-this-documentation) 也给出了关于构建该文档的一些说明,但没有太多细节。\r\n\r\n> If you have your own copy of the Galaxy source code, you can also generate your own version of this documentation. Run the following command from the Galaxy’s root:\r\n> ```\r\n> $ make docs\r\n> ```\r\n> The generated documentation will be in `doc/build/html/` and can be viewed with a web browser. Note that you will need to install Sphinx and other module dependencies which are listed in the Makefile in the Galaxy root folder.\r\n\r\n下面我们来详细分解一下 `make docs` 这个命令具体执行的构建步骤。\r\n\r\n首先,在 Galaxy 根目录的执行 `make docs`,主要是执行了该目录下 [Makefile](https://github.com/galaxyproject/galaxy/blob/dev/Makefile) 中的这几句命令:\r\n```\r\ndocs: ## Generate HTML documentation.\r\n# Run following commands to setup the Python portion of the requirements:\r\n# $ ./scripts/common_startup.sh\r\n# $ . .venv/bin/activate\r\n# $ pip install -r requirements.txt -r lib/galaxy/dependencies/dev-requirements.txt\r\n\t$(IN_VENV) $(MAKE) -C doc clean\r\n\t$(IN_VENV) $(MAKE) -C doc html\r\n```\r\n- `$(MAKE)`就是预设的 `make` 这个命令的名称(或者路径)。 \r\n- `-C`:到指定目录下读取 Makefile 文件并执行(给出指定的目录的路径)。 \r\n\r\n第二步,读取 `doc` 目录下的 [Makefile](https://github.com/galaxyproject/galaxy/blob/dev/doc/Makefile) 文件,并执行 `make html`。\r\n```\r\nhtml: $(GENERATED_RST)\r\n\t$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html\r\n\t@echo\r\n\t@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."\r\n```\r\n\r\n结合其中的一些参数,其实最终就是执行了下面这个命令完成最终的构建。\r\n```bash\r\nsphinx-build -b html -d build/doctrees source build/html\r\n```\r\n\r\n- sphinx-build [OPTIONS] SOURCEDIR OUTPUTDIR [FILENAMES...]\r\n- sourcedir:path to documentation source files\r\n- outputdir:path to output directory\r\n- `-b`:BUILDER,builder to use (default: html)\r\n\r\n了解了以上几个步骤后,我们就可以把 Galaxy 根目录的 doc 目录单独拎出来,通过 Sphinx 的命令实现独立构建部署。\r\n\r\n## 1. 安装必须依赖\r\n\r\n主要包括三个依赖。\r\n```\r\npip3 install Sphinx sphinx_rtd_theme myst_parser\r\n```\r\n\r\n## 2. 修改配置\r\n\r\n由于 `sphinx-build` 会读取 `source/conf.py` 并执行,但这个文件调用了 [`galaxy.version`](https://github.com/galaxyproject/galaxy/blob/dev/lib/galaxy/version.py) 模块:\r\n![No module named \'galaxy\'](https://shub.weiyan.tech/kgarden/2024/01/no-galaxy-version.png)\r\n\r\n所以,如果我们想要把 `galaxy/doc` 和 Galaxy 独立开来进行部署,就需要修改一下 `source/conf.py`:\r\n```python\r\n# The short X.Y version.\r\n#from galaxy.version import (\r\n# VERSION,\r\n# VERSION_MAJOR,\r\n#)\r\n\r\nVERSION_MAJOR = "23.1"\r\nVERSION_MINOR = "5.dev0"\r\nVERSION = VERSION_MAJOR + (f".{VERSION_MINOR}" if VERSION_MINOR else "")\r\n```\r\n\r\n## 3. 执行构建\r\n```bash\r\n$ sphinx-build -b html -d build/doctrees source build/html\r\nRunning Sphinx v7.2.6\r\nmaking output directory... done\r\nmyst v2.0.0: MdParserConfig(commonmark_only=False, gfm_only=False, enable_extensions={\'deflist\', \'attrs_block\', \'substitution\'}, disable_syntax=[], all_links_external=False, url_schemes=(\'http\', \'https\', \'mailto\', \'ftp\'), ref_domains=None, fence_as_directive=set(), number_code_blocks=[], title_to_header=False, heading_anchors=5, heading_slug_func=, html_meta={}, footnote_transition=True, words_per_minute=200, substitutions={}, linkify_fuzzy_links=True, dmath_allow_labels=True, dmath_allow_space=True, dmath_allow_digits=True, dmath_double_inline=False, update_mathjax=True, mathjax_classes=\'tex2jax_process|mathjax_process|math|output_area\', enable_checkboxes=False, suppress_warnings=[], highlight_code_blocks=True)\r\nloading intersphinx inventory from https://docs.python.org/3/objects.inv...\r\nloading intersphinx inventory from https://requests.readthedocs.io/en/master/objects.inv...\r\nintersphinx inventory has moved: https://requests.readthedocs.io/en/master/objects.inv -> https://requests.readthedocs.io/en/latest/objects.inv\r\nbuilding [mo]: targets for 0 po files that are out of date\r\nwriting output... \r\nbuilding [html]: targets for 332 source files that are out of date\r\nupdating environment: [new config] 332 added, 0 changed, 0 removed\r\nreading sources... [100%] ts_api_doc\r\n\r\n...\r\n\r\ngenerating indices... genindex done\r\nhighlighting module code... \r\nwriting additional pages... search done\r\ncopying images... [100%] releases/images/23.1-hdf5.png\r\ndumping search index in English (code: en)... done\r\ndumping object inventory... done\r\nbuild succeeded, 1223 warnings.\r\n\r\nThe HTML pages are in build/html.\r\n```\r\n\r\n最后生成的静态文件都保存在了 `build/html` 目录,我们可以借助 NGINX 或者其他 Pages 就可以直接看到一个一模一样对应当前 Repo 版本的 Galaxy Project 文档了。', 'bodyText': 'https://docs.galaxyproject.org/ 是 Galaxy Project 官方的文档地址链接,这是一个基于 Sphinx + Read the Docs 的文档站点。如果我们也想要创建一个这样一模一样的 Galaxy 文档需要怎么操作呢?\n\n虽然 Galaxy 官方文档 也给出了关于构建该文档的一些说明,但没有太多细节。\n\nIf you have your own copy of the Galaxy source code, you can also generate your own version of this documentation. Run the following command from the Galaxy’s root:\n$ make docs\n\nThe generated documentation will be in doc/build/html/ and can be viewed with a web browser. Note that you will need to install Sphinx and other module dependencies which are listed in the Makefile in the Galaxy root folder.\n\n下面我们来详细分解一下 make docs 这个命令具体执行的构建步骤。\n首先,在 Galaxy 根目录的执行 make docs,主要是执行了该目录下 Makefile 中的这几句命令:\ndocs: ## Generate HTML documentation.\n# Run following commands to setup the Python portion of the requirements:\n# $ ./scripts/common_startup.sh\n# $ . .venv/bin/activate\n# $ pip install -r requirements.txt -r lib/galaxy/dependencies/dev-requirements.txt\n\t$(IN_VENV) $(MAKE) -C doc clean\n\t$(IN_VENV) $(MAKE) -C doc html\n\n\n$(MAKE)就是预设的 make 这个命令的名称(或者路径)。\n-C:到指定目录下读取 Makefile 文件并执行(给出指定的目录的路径)。\n\n第二步,读取 doc 目录下的 Makefile 文件,并执行 make html。\nhtml: $(GENERATED_RST)\n\t$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html\n\t@echo\n\t@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."\n\n结合其中的一些参数,其实最终就是执行了下面这个命令完成最终的构建。\nsphinx-build -b html -d build/doctrees source build/html\n\nsphinx-build [OPTIONS] SOURCEDIR OUTPUTDIR [FILENAMES...]\nsourcedir:path to documentation source files\noutputdir:path to output directory\n-b:BUILDER,builder to use (default: html)\n\n了解了以上几个步骤后,我们就可以把 Galaxy 根目录的 doc 目录单独拎出来,通过 Sphinx 的命令实现独立构建部署。\n1. 安装必须依赖\n主要包括三个依赖。\npip3 install Sphinx sphinx_rtd_theme myst_parser\n\n2. 修改配置\n由于 sphinx-build 会读取 source/conf.py 并执行,但这个文件调用了 galaxy.version 模块:\n\n所以,如果我们想要把 galaxy/doc 和 Galaxy 独立开来进行部署,就需要修改一下 source/conf.py:\n# The short X.Y version.\n#from galaxy.version import (\n# VERSION,\n# VERSION_MAJOR,\n#)\n\nVERSION_MAJOR = "23.1"\nVERSION_MINOR = "5.dev0"\nVERSION = VERSION_MAJOR + (f".{VERSION_MINOR}" if VERSION_MINOR else "")\n3. 执行构建\n$ sphinx-build -b html -d build/doctrees source build/html\nRunning Sphinx v7.2.6\nmaking output directory... done\nmyst v2.0.0: MdParserConfig(commonmark_only=False, gfm_only=False, enable_extensions={\'deflist\', \'attrs_block\', \'substitution\'}, disable_syntax=[], all_links_external=False, url_schemes=(\'http\', \'https\', \'mailto\', \'ftp\'), ref_domains=None, fence_as_directive=set(), number_code_blocks=[], title_to_header=False, heading_anchors=5, heading_slug_func=, html_meta={}, footnote_transition=True, words_per_minute=200, substitutions={}, linkify_fuzzy_links=True, dmath_allow_labels=True, dmath_allow_space=True, dmath_allow_digits=True, dmath_double_inline=False, update_mathjax=True, mathjax_classes=\'tex2jax_process|mathjax_process|math|output_area\', enable_checkboxes=False, suppress_warnings=[], highlight_code_blocks=True)\nloading intersphinx inventory from https://docs.python.org/3/objects.inv...\nloading intersphinx inventory from https://requests.readthedocs.io/en/master/objects.inv...\nintersphinx inventory has moved: https://requests.readthedocs.io/en/master/objects.inv -> https://requests.readthedocs.io/en/latest/objects.inv\nbuilding [mo]: targets for 0 po files that are out of date\nwriting output... \nbuilding [html]: targets for 332 source files that are out of date\nupdating environment: [new config] 332 added, 0 changed, 0 removed\nreading sources... [100%] ts_api_doc\n\n...\n\ngenerating indices... genindex done\nhighlighting module code... \nwriting additional pages... search done\ncopying images... [100%] releases/images/23.1-hdf5.png\ndumping search index in English (code: en)... done\ndumping object inventory... done\nbuild succeeded, 1223 warnings.\n\nThe HTML pages are in build/html.\n最后生成的静态文件都保存在了 build/html 目录,我们可以借助 NGINX 或者其他 Pages 就可以直接看到一个一模一样对应当前 Repo 版本的 Galaxy Project 文档了。', 'bodyHTML': '

https://docs.galaxyproject.org/ 是 Galaxy Project 官方的文档地址链接,这是一个基于 Sphinx + Read the Docs 的文档站点。如果我们也想要创建一个这样一模一样的 Galaxy 文档需要怎么操作呢?

\n\n

虽然 Galaxy 官方文档 也给出了关于构建该文档的一些说明,但没有太多细节。

\n
\n

If you have your own copy of the Galaxy source code, you can also generate your own version of this documentation. Run the following command from the Galaxy’s root:

\n
$ make docs\n
\n

The generated documentation will be in doc/build/html/ and can be viewed with a web browser. Note that you will need to install Sphinx and other module dependencies which are listed in the Makefile in the Galaxy root folder.

\n
\n

下面我们来详细分解一下 make docs 这个命令具体执行的构建步骤。

\n

首先,在 Galaxy 根目录的执行 make docs,主要是执行了该目录下 Makefile 中的这几句命令:

\n
docs: ## Generate HTML documentation.\n# Run following commands to setup the Python portion of the requirements:\n#   $ ./scripts/common_startup.sh\n#   $ . .venv/bin/activate\n#   $ pip install -r requirements.txt -r lib/galaxy/dependencies/dev-requirements.txt\n\t$(IN_VENV) $(MAKE) -C doc clean\n\t$(IN_VENV) $(MAKE) -C doc html\n
\n
    \n
  • $(MAKE)就是预设的 make 这个命令的名称(或者路径)。
  • \n
  • -C:到指定目录下读取 Makefile 文件并执行(给出指定的目录的路径)。
  • \n
\n

第二步,读取 doc 目录下的 Makefile 文件,并执行 make html

\n
html: $(GENERATED_RST)\n\t$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html\n\t@echo\n\t@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."\n
\n

结合其中的一些参数,其实最终就是执行了下面这个命令完成最终的构建。

\n
sphinx-build -b html -d build/doctrees source build/html
\n
    \n
  • sphinx-build [OPTIONS] SOURCEDIR OUTPUTDIR [FILENAMES...]
  • \n
  • sourcedir:path to documentation source files
  • \n
  • outputdir:path to output directory
  • \n
  • -b:BUILDER,builder to use (default: html)
  • \n
\n

了解了以上几个步骤后,我们就可以把 Galaxy 根目录的 doc 目录单独拎出来,通过 Sphinx 的命令实现独立构建部署。

\n

1. 安装必须依赖

\n

主要包括三个依赖。

\n
pip3 install Sphinx sphinx_rtd_theme myst_parser\n
\n

2. 修改配置

\n

由于 sphinx-build 会读取 source/conf.py 并执行,但这个文件调用了 galaxy.version 模块:
\nNo module named \'galaxy\'

\n

所以,如果我们想要把 galaxy/doc 和 Galaxy 独立开来进行部署,就需要修改一下 source/conf.py

\n
# The short X.Y version.\n#from galaxy.version import (\n#    VERSION,\n#    VERSION_MAJOR,\n#)\n\nVERSION_MAJOR = "23.1"\nVERSION_MINOR = "5.dev0"\nVERSION = VERSION_MAJOR + (f".{VERSION_MINOR}" if VERSION_MINOR else "")
\n

3. 执行构建

\n
$ sphinx-build -b html -d build/doctrees   source build/html\nRunning Sphinx v7.2.6\nmaking output directory... done\nmyst v2.0.0: MdParserConfig(commonmark_only=False, gfm_only=False, enable_extensions={\'deflist\', \'attrs_block\', \'substitution\'}, disable_syntax=[], all_links_external=False, url_schemes=(\'http\', \'https\', \'mailto\', \'ftp\'), ref_domains=None, fence_as_directive=set(), number_code_blocks=[], title_to_header=False, heading_anchors=5, heading_slug_func=<function make_id at 0x7f46201a6a60>, html_meta={}, footnote_transition=True, words_per_minute=200, substitutions={}, linkify_fuzzy_links=True, dmath_allow_labels=True, dmath_allow_space=True, dmath_allow_digits=True, dmath_double_inline=False, update_mathjax=True, mathjax_classes=\'tex2jax_process|mathjax_process|math|output_area\', enable_checkboxes=False, suppress_warnings=[], highlight_code_blocks=True)\nloading intersphinx inventory from https://docs.python.org/3/objects.inv...\nloading intersphinx inventory from https://requests.readthedocs.io/en/master/objects.inv...\nintersphinx inventory has moved: https://requests.readthedocs.io/en/master/objects.inv -> https://requests.readthedocs.io/en/latest/objects.inv\nbuilding [mo]: targets for 0 po files that are out of date\nwriting output... \nbuilding [html]: targets for 332 source files that are out of date\nupdating environment: [new config] 332 added, 0 changed, 0 removed\nreading sources... [100%] ts_api_doc\n\n...\n\ngenerating indices... genindex done\nhighlighting module code... \nwriting additional pages... search done\ncopying images... [100%] releases/images/23.1-hdf5.png\ndumping search index in English (code: en)... done\ndumping object inventory... done\nbuild succeeded, 1223 warnings.\n\nThe HTML pages are in build/html.
\n

最后生成的静态文件都保存在了 build/html 目录,我们可以借助 NGINX 或者其他 Pages 就可以直接看到一个一模一样对应当前 Repo 版本的 Galaxy Project 文档了。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '3.1-Galaxy'}, 'labels': {'nodes': [{'name': '公众号'}, {'name': '3.1.x-GalaxyOther'}]}, 'comments': {'nodes': []}}, {'title': '更新记录', 'number': 45, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/45', 'createdAt': '2024-01-04T05:50:47Z', 'lastEditedAt': '2024-07-16T05:55:41Z', 'updatedAt': '2024-07-16T05:55:43Z', 'body': '记录一下本知识仓库 [Knowledge-Garden](https://github.com/shenweiyan/Knowledge-Garden) 的一些主要更新记录。\r\n\r\n\r\n\r\n#### 2024-07-16\r\n- GitHub Pages 域名由 [doc.weiyan.cc](https://doc.weiyan.cc/) 变更为 [gh-pages.weiyan.cc](https://gh-pages.weiyan.cc/)。\r\n\r\n#### 2024-01-04 \r\n- 域名 `weiyan.cc` DNS 从 Cloudflare 转回阿里云。 \r\n- 把站点从 [Cloudflare Pages](https://pages.cloudflare.com/) 转移到 [Netlify](https://app.netlify.com/),绑定 [www.weiyan.cc](https://www.weiyan.cc/),实现 [weiyan.cc](https://weiyan.cc/) 重定向到 www 主域名 (Redirects automatically to primary domain)。\r\n\r\n#### 2023-11-28 \r\n- 镜像站点([weiyan.pages.dev](https://weiyan.pages.dev/))部署到 [Cloudflare Pages](https://pages.cloudflare.com/),绑定自定义域名 [weiyan.cc](https://weiyan.cc/)。 \r\n\r\n#### 2023-10-16 \r\n- GitHub 正式创建 [Knowledge-Garden](https://github.com/shenweiyan/Knowledge-Garden) 仓库,开启 GitHub Pages,绑定 [doc.weiyan.cc](https://doc.weiyan.cc/)。', 'bodyText': '记录一下本知识仓库 Knowledge-Garden 的一些主要更新记录。\n\n2024-07-16\n\nGitHub Pages 域名由 doc.weiyan.cc 变更为 gh-pages.weiyan.cc。\n\n2024-01-04\n\n域名 weiyan.cc DNS 从 Cloudflare 转回阿里云。\n把站点从 Cloudflare Pages 转移到 Netlify,绑定 www.weiyan.cc,实现 weiyan.cc 重定向到 www 主域名 (Redirects automatically to primary domain)。\n\n2023-11-28\n\n镜像站点(weiyan.pages.dev)部署到 Cloudflare Pages,绑定自定义域名 weiyan.cc。\n\n2023-10-16\n\nGitHub 正式创建 Knowledge-Garden 仓库,开启 GitHub Pages,绑定 doc.weiyan.cc。', 'bodyHTML': '

记录一下本知识仓库 Knowledge-Garden 的一些主要更新记录。

\n\n

2024-07-16

\n\n

2024-01-04

\n\n

2023-11-28

\n\n

2023-10-16

\n', 'author': {'login': 'shenweiyan'}, 'category': {'name': '0.1-站点'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '不要使用 requirements.txt', 'number': 44, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/44', 'createdAt': '2024-01-03T07:50:27Z', 'lastEditedAt': '2024-01-03T07:55:06Z', 'updatedAt': '2024-01-03T07:55:06Z', 'body': '> 作者:[Miikka Koskinen](https://miikka.me/) \r\n> 编译:[沈维燕](https://weiyan.cc) \r\n> 时间:原文发表于 2023-10-31 \r\n> 原文:[Do not use requirements.txt](https://quanttype.net/posts/2023-10-31-do-not-use-requirements.txt.html)\r\n\r\n你是否在用 Python 开发后端服务?我有两条建议:\r\n\r\n- 不要使用 `pip` 和 `requirements.txt` 来管理 Python 依赖。它们缺乏一些应该内置的关键功能。\r\n- 改用 [Poetry](https://python-poetry.org/)。\r\n\r\n\r\n\r\n对我来说,第一条建议毋庸置疑。第二条则更具有暂时性:Poetry 是一个很好的选择,但并非唯一值得考虑的选择。\r\n\r\n我将在下面进行解释。\r\n\r\n请注意:如果你使用 Python 做其他事情而不是构建后端服务,那么本文中的建议可能并不适用于你。例如,如果你是[一个正在迁移 `setup.py` 的库开发者](https://gregoryszorc.com/blog/2023/10/30/my-user-experience-porting-off-setup.py/),Poetry 并不明显是一个完美的选择。\r\n\r\n## PIP 缺失的功能\r\n[pip](https://pypi.org/project/pip/) 是一个工具,你可以用它从 [The Python Package Index (PyPI)](https://pypi.org/) 中安装软件包。它随 Python 一起安装,如果你是 Python 开发者,你可能已经多次使用过它。\r\n\r\n管理 Python 项目依赖的传统方式是将它们列在一个名为 `requirements.txt` 的文件中,并使用 `pip install -r requirements.txt` 进行安装。然而,`pip` 被设计成一个软件包安装工具,而不是一个功能齐全的项目工作流工具。**pip 缺乏两个关键功能,即依赖的锁定文件 (dependency lockfiles) 和虚拟环境的自动管理(automatic management of virtualenvs)。**\r\n\r\n## 依赖锁定文件\r\n如果你希望在所有环境中(比如你的笔记本电脑、持续集成(CI)、生产环境)获得相同的行为,你需要锁定你的依赖项及其传递依赖的版本。你可以在 `requirements.txt` 中锁定你直接依赖的版本,例如,使用 `requests==2.31.0` 而不是 `requests`。\r\n\r\n然而,pip 不会锁定传递依赖的版本。这可以通过使用 [pip-tools](https://github.com/jazzband/pip-tools) 来解决,将 `requirements.txt` 扩展成一个列出完整依赖图的文件,包括准确版本和构件的校验和(checksums for the artifacts)。pip-tools 很不错,但你需要自行设置并弄清楚它如何适应你的工作流程。\r\n\r\n在其他编程语言中,这个功能是基本要求的 - 例如,npm 多年来一直有 `package-lock.json`,Cargo 也有 `Cargo.lock`。这个功能实在应该是一个项目工作流工具中的内置功能。\r\n\r\n## 虚拟环境的自动管理\r\n\r\n在 Python 中创建隔离环境的方式是使用 [virtualenvs](https://docs.python.org/3/library/venv.html)。传统上,你需要手动管理它们:通过一个 shell 命令创建一个(比如 `python -m venv example` 来创建名为 `example` 的虚拟环境),当你想要使用它时,需要用另一个 shell 命令来激活它。\r\n\r\n这容易出错:忘记激活虚拟环境或者激活错误的虚拟环境是常见的错误。有一堆的解决方法。例如,你可以使用 [pyenv-virtualenv](https://github.com/pyenv/pyenv-virtualenv),在进入项目目录时让你的 shell 自动激活一个虚拟环境。[direnv](https://github.com/direnv/direnv/wiki/Python) 也可以做到。\r\n\r\n同样,这也应该成为工作流工具中的一个内置功能。你不应该需要将多个工具粘合在一起。你不会听到 npm 或 Cargo 用户在虚拟环境上遇到问题的。\r\n\r\n## Poetry 及其他选择\r\n\r\n幸运的是,许多人已经意识到这些问题并努力解决它们。不太幸运的是,这导致了大量的 Python 项目工作流工具涌现。那么该如何选择呢?\r\n\r\n我的建议是:**选择 [Poetry](https://python-poetry.org/docs/)**。它有锁定文件,有虚拟环境管理,而且很受欢迎且在积极开发中。根据我的经验,它并不完美,但是它起作用。\r\n\r\n你也可以考虑 [Hatch](https://hatch.pypa.io/latest/) 或 [PDM](https://github.com/pdm-project/pdm)。它们与 Poetry 相似。我自己没有使用过它们,但我听说其他人成功地使用了它们。Hatch 似乎在库作者 (library authors) 中特别受欢迎。\r\n\r\n如果你正在寻找一个更强大的选项,可以处理多个子项目,[Pants 构建系统](https://www.pantsbuild.org/)在 Python 支持方面做得很好。然而,它的学习曲线相对陡峭。\r\n\r\n最后,如果你正在寻找一个类似 rustup 那样可以为你安装 Python 的解决方案,那么有 [rye](https://github.com/mitsuhiko/rye)。它是新的实验性工具,但也许它对你来说是正确的选择?\r\n\r\n## 哪个是权威的工作流工具?\r\n\r\n如果 Python 自带一个权威的项目工作流工具会很好。很多人希望 pip 成为这样一个工具。Node.js 自带 npm,Rust 自带 Cargo,那么为什么 Python 就不能有一个呢?为什么会有这么多竞争的选择呢?\r\n\r\n据我所知,最大的障碍是,由于 Python 被广泛使用且用于许多不同的用例,制定一个通用的官方解决方案是困难且缓慢的(并且资金不足的)工作。另外,也不清楚 pip 是否适合这些功能。\r\n\r\n如果你想了解更多信息,请阅读和听取这些与我不同、深度参与 Python 社区的人的意见: \r\n- Stargirl (Thea Flowers) on Fediverse:《[所以你想解决 Python 打包问题:一个实用指南](https://hachyderm.io/@stargirl/109697057391904145)》\r\n- Pradyun Gedam:《[关于 Python 打包生态系统的思考](https://pradyunsg.me/blog/2023/01/21/thoughts-on-python-packaging/)》\r\n- Talk Python to Me (podcast):《[重新构想 Python 的打包工作流程](https://talkpython.fm/episodes/show/406/reimagining-pythons-packaging-workflows)》\r\n\r\n## 关于 Clojure \r\n\r\n阅读我的博客的 Clojure 开发者可能会问:嘿,Clojure 怎么样?为什么我们没有锁定文件呢?这是一个很好的问题!\r\n\r\nClojure 社区通过始终使用明确的版本而不是版本范围来解决了这个问题,即使在库中也是如此。版本描述实际上支持范围,但没有人会使用它们。这样,只要版本解析算法稳定,你总是会得到相同的版本。\r\n\r\n理论上,传递依赖项版本不匹配可能是一个问题,但 Clojure 支持一种编码风格,很少引起问题。\r\n\r\n相比之下,在 Python 和 Node.js 社区,通常期望库列出其依赖项的版本范围,而软件包管理工具会抱怨版本不匹配的问题。', 'bodyText': '作者:Miikka Koskinen\n编译:沈维燕\n时间:原文发表于 2023-10-31\n原文:Do not use requirements.txt\n\n你是否在用 Python 开发后端服务?我有两条建议:\n\n不要使用 pip 和 requirements.txt 来管理 Python 依赖。它们缺乏一些应该内置的关键功能。\n改用 Poetry。\n\n\n对我来说,第一条建议毋庸置疑。第二条则更具有暂时性:Poetry 是一个很好的选择,但并非唯一值得考虑的选择。\n我将在下面进行解释。\n请注意:如果你使用 Python 做其他事情而不是构建后端服务,那么本文中的建议可能并不适用于你。例如,如果你是一个正在迁移 setup.py 的库开发者,Poetry 并不明显是一个完美的选择。\nPIP 缺失的功能\npip 是一个工具,你可以用它从 The Python Package Index (PyPI) 中安装软件包。它随 Python 一起安装,如果你是 Python 开发者,你可能已经多次使用过它。\n管理 Python 项目依赖的传统方式是将它们列在一个名为 requirements.txt 的文件中,并使用 pip install -r requirements.txt 进行安装。然而,pip 被设计成一个软件包安装工具,而不是一个功能齐全的项目工作流工具。pip 缺乏两个关键功能,即依赖的锁定文件 (dependency lockfiles) 和虚拟环境的自动管理(automatic management of virtualenvs)。\n依赖锁定文件\n如果你希望在所有环境中(比如你的笔记本电脑、持续集成(CI)、生产环境)获得相同的行为,你需要锁定你的依赖项及其传递依赖的版本。你可以在 requirements.txt 中锁定你直接依赖的版本,例如,使用 requests==2.31.0 而不是 requests。\n然而,pip 不会锁定传递依赖的版本。这可以通过使用 pip-tools 来解决,将 requirements.txt 扩展成一个列出完整依赖图的文件,包括准确版本和构件的校验和(checksums for the artifacts)。pip-tools 很不错,但你需要自行设置并弄清楚它如何适应你的工作流程。\n在其他编程语言中,这个功能是基本要求的 - 例如,npm 多年来一直有 package-lock.json,Cargo 也有 Cargo.lock。这个功能实在应该是一个项目工作流工具中的内置功能。\n虚拟环境的自动管理\n在 Python 中创建隔离环境的方式是使用 virtualenvs。传统上,你需要手动管理它们:通过一个 shell 命令创建一个(比如 python -m venv example 来创建名为 example 的虚拟环境),当你想要使用它时,需要用另一个 shell 命令来激活它。\n这容易出错:忘记激活虚拟环境或者激活错误的虚拟环境是常见的错误。有一堆的解决方法。例如,你可以使用 pyenv-virtualenv,在进入项目目录时让你的 shell 自动激活一个虚拟环境。direnv 也可以做到。\n同样,这也应该成为工作流工具中的一个内置功能。你不应该需要将多个工具粘合在一起。你不会听到 npm 或 Cargo 用户在虚拟环境上遇到问题的。\nPoetry 及其他选择\n幸运的是,许多人已经意识到这些问题并努力解决它们。不太幸运的是,这导致了大量的 Python 项目工作流工具涌现。那么该如何选择呢?\n我的建议是:选择 Poetry。它有锁定文件,有虚拟环境管理,而且很受欢迎且在积极开发中。根据我的经验,它并不完美,但是它起作用。\n你也可以考虑 Hatch 或 PDM。它们与 Poetry 相似。我自己没有使用过它们,但我听说其他人成功地使用了它们。Hatch 似乎在库作者 (library authors) 中特别受欢迎。\n如果你正在寻找一个更强大的选项,可以处理多个子项目,Pants 构建系统在 Python 支持方面做得很好。然而,它的学习曲线相对陡峭。\n最后,如果你正在寻找一个类似 rustup 那样可以为你安装 Python 的解决方案,那么有 rye。它是新的实验性工具,但也许它对你来说是正确的选择?\n哪个是权威的工作流工具?\n如果 Python 自带一个权威的项目工作流工具会很好。很多人希望 pip 成为这样一个工具。Node.js 自带 npm,Rust 自带 Cargo,那么为什么 Python 就不能有一个呢?为什么会有这么多竞争的选择呢?\n据我所知,最大的障碍是,由于 Python 被广泛使用且用于许多不同的用例,制定一个通用的官方解决方案是困难且缓慢的(并且资金不足的)工作。另外,也不清楚 pip 是否适合这些功能。\n如果你想了解更多信息,请阅读和听取这些与我不同、深度参与 Python 社区的人的意见:\n\nStargirl (Thea Flowers) on Fediverse:《所以你想解决 Python 打包问题:一个实用指南》\nPradyun Gedam:《关于 Python 打包生态系统的思考》\nTalk Python to Me (podcast):《重新构想 Python 的打包工作流程》\n\n关于 Clojure\n阅读我的博客的 Clojure 开发者可能会问:嘿,Clojure 怎么样?为什么我们没有锁定文件呢?这是一个很好的问题!\nClojure 社区通过始终使用明确的版本而不是版本范围来解决了这个问题,即使在库中也是如此。版本描述实际上支持范围,但没有人会使用它们。这样,只要版本解析算法稳定,你总是会得到相同的版本。\n理论上,传递依赖项版本不匹配可能是一个问题,但 Clojure 支持一种编码风格,很少引起问题。\n相比之下,在 Python 和 Node.js 社区,通常期望库列出其依赖项的版本范围,而软件包管理工具会抱怨版本不匹配的问题。', 'bodyHTML': '
\n

作者:Miikka Koskinen
\n编译:沈维燕
\n时间:原文发表于 2023-10-31
\n原文:Do not use requirements.txt

\n
\n

你是否在用 Python 开发后端服务?我有两条建议:

\n
    \n
  • 不要使用 piprequirements.txt 来管理 Python 依赖。它们缺乏一些应该内置的关键功能。
  • \n
  • 改用 Poetry
  • \n
\n\n

对我来说,第一条建议毋庸置疑。第二条则更具有暂时性:Poetry 是一个很好的选择,但并非唯一值得考虑的选择。

\n

我将在下面进行解释。

\n

请注意:如果你使用 Python 做其他事情而不是构建后端服务,那么本文中的建议可能并不适用于你。例如,如果你是一个正在迁移 setup.py 的库开发者,Poetry 并不明显是一个完美的选择。

\n

PIP 缺失的功能

\n

pip 是一个工具,你可以用它从 The Python Package Index (PyPI) 中安装软件包。它随 Python 一起安装,如果你是 Python 开发者,你可能已经多次使用过它。

\n

管理 Python 项目依赖的传统方式是将它们列在一个名为 requirements.txt 的文件中,并使用 pip install -r requirements.txt 进行安装。然而,pip 被设计成一个软件包安装工具,而不是一个功能齐全的项目工作流工具。pip 缺乏两个关键功能,即依赖的锁定文件 (dependency lockfiles) 和虚拟环境的自动管理(automatic management of virtualenvs)。

\n

依赖锁定文件

\n

如果你希望在所有环境中(比如你的笔记本电脑、持续集成(CI)、生产环境)获得相同的行为,你需要锁定你的依赖项及其传递依赖的版本。你可以在 requirements.txt 中锁定你直接依赖的版本,例如,使用 requests==2.31.0 而不是 requests

\n

然而,pip 不会锁定传递依赖的版本。这可以通过使用 pip-tools 来解决,将 requirements.txt 扩展成一个列出完整依赖图的文件,包括准确版本和构件的校验和(checksums for the artifacts)。pip-tools 很不错,但你需要自行设置并弄清楚它如何适应你的工作流程。

\n

在其他编程语言中,这个功能是基本要求的 - 例如,npm 多年来一直有 package-lock.json,Cargo 也有 Cargo.lock。这个功能实在应该是一个项目工作流工具中的内置功能。

\n

虚拟环境的自动管理

\n

在 Python 中创建隔离环境的方式是使用 virtualenvs。传统上,你需要手动管理它们:通过一个 shell 命令创建一个(比如 python -m venv example 来创建名为 example 的虚拟环境),当你想要使用它时,需要用另一个 shell 命令来激活它。

\n

这容易出错:忘记激活虚拟环境或者激活错误的虚拟环境是常见的错误。有一堆的解决方法。例如,你可以使用 pyenv-virtualenv,在进入项目目录时让你的 shell 自动激活一个虚拟环境。direnv 也可以做到。

\n

同样,这也应该成为工作流工具中的一个内置功能。你不应该需要将多个工具粘合在一起。你不会听到 npm 或 Cargo 用户在虚拟环境上遇到问题的。

\n

Poetry 及其他选择

\n

幸运的是,许多人已经意识到这些问题并努力解决它们。不太幸运的是,这导致了大量的 Python 项目工作流工具涌现。那么该如何选择呢?

\n

我的建议是:选择 Poetry。它有锁定文件,有虚拟环境管理,而且很受欢迎且在积极开发中。根据我的经验,它并不完美,但是它起作用。

\n

你也可以考虑 HatchPDM。它们与 Poetry 相似。我自己没有使用过它们,但我听说其他人成功地使用了它们。Hatch 似乎在库作者 (library authors) 中特别受欢迎。

\n

如果你正在寻找一个更强大的选项,可以处理多个子项目,Pants 构建系统在 Python 支持方面做得很好。然而,它的学习曲线相对陡峭。

\n

最后,如果你正在寻找一个类似 rustup 那样可以为你安装 Python 的解决方案,那么有 rye。它是新的实验性工具,但也许它对你来说是正确的选择?

\n

哪个是权威的工作流工具?

\n

如果 Python 自带一个权威的项目工作流工具会很好。很多人希望 pip 成为这样一个工具。Node.js 自带 npm,Rust 自带 Cargo,那么为什么 Python 就不能有一个呢?为什么会有这么多竞争的选择呢?

\n

据我所知,最大的障碍是,由于 Python 被广泛使用且用于许多不同的用例,制定一个通用的官方解决方案是困难且缓慢的(并且资金不足的)工作。另外,也不清楚 pip 是否适合这些功能。

\n

如果你想了解更多信息,请阅读和听取这些与我不同、深度参与 Python 社区的人的意见:

\n\n

关于 Clojure

\n

阅读我的博客的 Clojure 开发者可能会问:嘿,Clojure 怎么样?为什么我们没有锁定文件呢?这是一个很好的问题!

\n

Clojure 社区通过始终使用明确的版本而不是版本范围来解决了这个问题,即使在库中也是如此。版本描述实际上支持范围,但没有人会使用它们。这样,只要版本解析算法稳定,你总是会得到相同的版本。

\n

理论上,传递依赖项版本不匹配可能是一个问题,但 Clojure 支持一种编码风格,很少引起问题。

\n

相比之下,在 Python 和 Node.js 社区,通常期望库列出其依赖项的版本范围,而软件包管理工具会抱怨版本不匹配的问题。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.2-编程'}, 'labels': {'nodes': [{'name': '翻译'}, {'name': '1.2.3-Python'}]}, 'comments': {'nodes': []}}, {'title': '技术人月刊(第 2 期 2024-01)', 'number': 43, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/43', 'createdAt': '2024-01-02T06:33:05Z', 'lastEditedAt': None, 'updatedAt': '2024-01-02T06:33:06Z', 'body': '## 文章', 'bodyText': '文章', 'bodyHTML': '

文章

', 'author': {'login': 'shenweiyan'}, 'category': {'name': 'x.2-月刊'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '基于 Matrix 协议的 Elements 通讯加密应用', 'number': 42, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/42', 'createdAt': '2023-12-28T09:17:08Z', 'lastEditedAt': '2023-12-30T09:56:12Z', 'updatedAt': '2023-12-30T09:56:13Z', 'body': 'Matrix 是一个开源、开放、轻量级、去中心化的即时聊天通讯协议,它是包括 deepin、Mozilla、Fedora、KDE、Archlinux、Debian 等开源社区均在广泛使用的即时聊天协议。\r\n\r\n\r\n\r\nElement 是 Matrix 官方性质的,基于 Web 技术的 Matrix 客户端实现,除了网页环境外,也有桌面客户端可用。可以在你所使用的发行版的应用商店或包管理工具中搜索 element-desktop 或近似名称来检索和安装此客户端,然后即可运行并登录你的帐号。\r\n\r\nElement 可以和 GitHub 的仓库实现关联,把 GitHub 仓库的诸多信息同步到 Element。', 'bodyText': 'Matrix 是一个开源、开放、轻量级、去中心化的即时聊天通讯协议,它是包括 deepin、Mozilla、Fedora、KDE、Archlinux、Debian 等开源社区均在广泛使用的即时聊天协议。\n\nElement 是 Matrix 官方性质的,基于 Web 技术的 Matrix 客户端实现,除了网页环境外,也有桌面客户端可用。可以在你所使用的发行版的应用商店或包管理工具中搜索 element-desktop 或近似名称来检索和安装此客户端,然后即可运行并登录你的帐号。\nElement 可以和 GitHub 的仓库实现关联,把 GitHub 仓库的诸多信息同步到 Element。', 'bodyHTML': '

Matrix 是一个开源、开放、轻量级、去中心化的即时聊天通讯协议,它是包括 deepin、Mozilla、Fedora、KDE、Archlinux、Debian 等开源社区均在广泛使用的即时聊天协议。

\n\n

Element 是 Matrix 官方性质的,基于 Web 技术的 Matrix 客户端实现,除了网页环境外,也有桌面客户端可用。可以在你所使用的发行版的应用商店或包管理工具中搜索 element-desktop 或近似名称来检索和安装此客户端,然后即可运行并登录你的帐号。

\n

Element 可以和 GitHub 的仓库实现关联,把 GitHub 仓库的诸多信息同步到 Element。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '阅读别人的博客', 'number': 41, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/41', 'createdAt': '2023-12-27T06:52:53Z', 'lastEditedAt': '2024-05-09T03:45:21Z', 'updatedAt': '2024-05-09T03:45:21Z', 'body': '很多时候阅读别人的博客(站点),总能发现一些好玩的人和事物。2023 年被[椒盐豆豉](https://blog.douchi.space/)的一篇《[2023 年了你为什么需要写博客](https://blog.douchi.space/2023-why-you-need-a-blog/)》所吸引,尤其是 **"博客是赛博空间的另一个你,也能反过来定义你"** 这一句,写出了很多心声。\r\n\r\n\r\n\r\n> 比较反感 "个人品牌" 这个过于商业化的说法,不写技术不写学术的非实名博客甚至起不到简历作用。但它确是比简历更 "像个人",比碎片化社交网络更全面展现我是怎样一个人的网络门面。当然这是我这个博客的用法,网上靠博客经营自己品牌的也比比皆是。总之,内容的自由度和高度的定制化让博客可以成为任何你想让它成为的东西。反之,博客写的久了,发现 "写博客" 也已经成为了自己(不只是线上) identity 的一部分——毕竟这是很多人认识我的渠道,也重塑了我的一部分自我认知。\r\n\r\n鉴于此,终于在个人的[站点](https://weiyan.cc/)新增加了一个[友链](https://weiyan.cc/flinks/)页面,把一部分有意思的博客与站点都以友链的方式放到了这里(会不定期清理失效域名、停更的博客)。\r\n', 'bodyText': '很多时候阅读别人的博客(站点),总能发现一些好玩的人和事物。2023 年被椒盐豆豉的一篇《2023 年了你为什么需要写博客》所吸引,尤其是 "博客是赛博空间的另一个你,也能反过来定义你" 这一句,写出了很多心声。\n\n\n比较反感 "个人品牌" 这个过于商业化的说法,不写技术不写学术的非实名博客甚至起不到简历作用。但它确是比简历更 "像个人",比碎片化社交网络更全面展现我是怎样一个人的网络门面。当然这是我这个博客的用法,网上靠博客经营自己品牌的也比比皆是。总之,内容的自由度和高度的定制化让博客可以成为任何你想让它成为的东西。反之,博客写的久了,发现 "写博客" 也已经成为了自己(不只是线上) identity 的一部分——毕竟这是很多人认识我的渠道,也重塑了我的一部分自我认知。\n\n鉴于此,终于在个人的站点新增加了一个友链页面,把一部分有意思的博客与站点都以友链的方式放到了这里(会不定期清理失效域名、停更的博客)。', 'bodyHTML': '

很多时候阅读别人的博客(站点),总能发现一些好玩的人和事物。2023 年被椒盐豆豉的一篇《2023 年了你为什么需要写博客》所吸引,尤其是 "博客是赛博空间的另一个你,也能反过来定义你" 这一句,写出了很多心声。

\n\n
\n

比较反感 "个人品牌" 这个过于商业化的说法,不写技术不写学术的非实名博客甚至起不到简历作用。但它确是比简历更 "像个人",比碎片化社交网络更全面展现我是怎样一个人的网络门面。当然这是我这个博客的用法,网上靠博客经营自己品牌的也比比皆是。总之,内容的自由度和高度的定制化让博客可以成为任何你想让它成为的东西。反之,博客写的久了,发现 "写博客" 也已经成为了自己(不只是线上) identity 的一部分——毕竟这是很多人认识我的渠道,也重塑了我的一部分自我认知。

\n
\n

鉴于此,终于在个人的站点新增加了一个友链页面,把一部分有意思的博客与站点都以友链的方式放到了这里(会不定期清理失效域名、停更的博客)。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'Pandas 处理 Excel 常用方法技巧', 'number': 40, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/40', 'createdAt': '2023-12-26T06:12:05Z', 'lastEditedAt': '2024-02-01T05:37:17Z', 'updatedAt': '2024-02-01T05:37:17Z', 'body': '在使用 Pandas 前需要学习了解一下 Series 和 DataFrame 的基本数据结构和索引的相关概念,之后就可以练习基本的 Excel操作。Pandas 读取一个 Excel 文件后会将其转化为 DataFrame 对象,每一列或行就是一个 Series 对象。这里我们看下如何对一个 excel 进行读写,以及 Sheet、行列、表头处理的一些常用技巧。\r\n\r\n## 读取 Excel\r\n\r\n如果您想读取 Excel 表格中的数据,可以使用 `read_excel()` 方法,其语法格式如下:\r\n\r\n```\r\npd.read_excel(io, sheet_name=0, header=0, names=None, index_col=None,\r\n usecols=None, squeeze=False,dtype=None, engine=None,\r\n converters=None, true_values=None, false_values=None,\r\n skiprows=None, nrows=None, na_values=None, parse_dates=False,\r\n date_parser=None, thousands=None, comment=None, skipfooter=0,\r\n convert_float=True, **kwds)\r\n```\r\n\r\n下表对常用参数做了说明:\r\n\r\n|参数名称|说明|\r\n|:----|:----|\r\n|io|表示 Excel 文件的存储路径。|\r\n|sheet_name|要读取的工作表名称,默认0,即读取第一个工作表作为 DataFrame(一定要加`sheet_name=None`,才能读取出所有的 sheet,否则默认读取第一个 sheet)。|\r\n|header|指定作为列名的行,默认0,即取第一行的值为列名;若数据不包含列名,则设定 header = None。若将其设置为 header=2,则表示将前两行作为多重索引。|\r\n|names|一般适用于Excel缺少列名,或者需要重新定义列名的情况;names的长度必须等于Excel表格列的长度,否则会报错。|\r\n|index_col|用做行索引的列,可以是工作表的列名称,如 index_col = \'列名\',也可以是整数或者列表。|\r\n|usecols|int或list类型,默认为None,表示需要读取所有列。|\r\n|squeeze|boolean,默认为False,如果解析的数据只包含一列,则返回一个Series。|\r\n|converters|规定每一列的数据类型。|\r\n|skiprows|接受一个列表,表示跳过指定行数的数据,从头部第一行开始。|\r\n|nrows|需要读取的行数。|\r\n|skipfooter|接受一个列表,省略指定行数的数据,从尾部最后一行开始。|\r\n\r\n示例如下所示:\r\n```python\r\nimport pandas as pd\r\n\r\n# 读取所有Sheet\r\ndf = pd.read_excel(\'example.xlsx\', sheet_name=None)\r\n\r\n# 读取第一个、第二个和名为"Sheet5"的工作表作为 DataFrame 的字典\r\ndf = pd.read_excel(\'example.xlsx\', sheet_name=[0, 1, "Sheet5"])\r\n```\r\n\r\n## 获取行数和列数\r\n```python\r\nimport pandas as pd\r\n \r\ndf = pd.read_excel(\'example.xlsx\')\r\n# 行索引\r\nprint(df.index) \r\n# RangeIndex(start=0, stop=3747, step=1)\r\n\r\n# 输出元祖,分别为行数和列数,默认第一行是表头不算行数\r\nprint(df.shape) \r\n# (3747, 4)\r\n```\r\n\r\n## 获取表头\r\n`read_excel` 默认是把 excel 的第一行当成表头。注意:如果 `read_excel` 的 `sheet_name=None`,读取的是所有 excel 的 sheet_name(key) 和 sheet_values(values) 组成的字典,`df.keys()` 的结果是所有 sheet_name,即名字(字典的键)。\r\n\r\n### 获取第一个 sheet\r\n这时候 `df.keys()` 和 `df.columns` 的结果是一样的,都是第一个 sheet 的表头。\r\n\r\n```python\r\nimport pandas as pd\r\n \r\ndf = pd.read_excel(\'input.xlsx\')\r\nprint(df.keys())\r\nprint(\'---------------\')\r\nprint(df.columns)\r\n```\r\n\r\n### 获取所有 sheet\r\n```python\r\nimport pandas as pd\r\n \r\n# 参数为 None 代表读取所有 sheet\r\ndf = pd.read_excel(\'input.xlsx\',sheet_name=None)\r\n\r\n# 获取所有sheet名字, 如果read_excel参数不是None, 则df.keys()为表头\r\nsheet_names = list(df.keys())\r\nprint(sheet_names)\r\n```\r\n\r\n## 参考资料\r\n1. 老董,《[pandas获取excel的行数,列数,表头,sheet,前后行等数据](https://www.python66.com/pandasshujufenxi/268.html)》,[Python编程网](https://www.python66.com/)\r\n2. 《[Pandas Excel读写操作详解](https://c.biancheng.net/pandas/excel.html)》,[C语言中文网](https://c.biancheng.net/)\r\n3. 《[pandas.read_excel — pandas 2.1.4 documentation](https://pandas.pydata.org/docs/reference/api/pandas.read_excel.html)》,[pandas documentation — pandas 2.1.4 documentation](https://pandas.pydata.org/docs/index.html)', 'bodyText': '在使用 Pandas 前需要学习了解一下 Series 和 DataFrame 的基本数据结构和索引的相关概念,之后就可以练习基本的 Excel操作。Pandas 读取一个 Excel 文件后会将其转化为 DataFrame 对象,每一列或行就是一个 Series 对象。这里我们看下如何对一个 excel 进行读写,以及 Sheet、行列、表头处理的一些常用技巧。\n读取 Excel\n如果您想读取 Excel 表格中的数据,可以使用 read_excel() 方法,其语法格式如下:\npd.read_excel(io, sheet_name=0, header=0, names=None, index_col=None,\n usecols=None, squeeze=False,dtype=None, engine=None,\n converters=None, true_values=None, false_values=None,\n skiprows=None, nrows=None, na_values=None, parse_dates=False,\n date_parser=None, thousands=None, comment=None, skipfooter=0,\n convert_float=True, **kwds)\n\n下表对常用参数做了说明:\n\n\n\n参数名称\n说明\n\n\n\n\nio\n表示 Excel 文件的存储路径。\n\n\nsheet_name\n要读取的工作表名称,默认0,即读取第一个工作表作为 DataFrame(一定要加sheet_name=None,才能读取出所有的 sheet,否则默认读取第一个 sheet)。\n\n\nheader\n指定作为列名的行,默认0,即取第一行的值为列名;若数据不包含列名,则设定 header = None。若将其设置为 header=2,则表示将前两行作为多重索引。\n\n\nnames\n一般适用于Excel缺少列名,或者需要重新定义列名的情况;names的长度必须等于Excel表格列的长度,否则会报错。\n\n\nindex_col\n用做行索引的列,可以是工作表的列名称,如 index_col = \'列名\',也可以是整数或者列表。\n\n\nusecols\nint或list类型,默认为None,表示需要读取所有列。\n\n\nsqueeze\nboolean,默认为False,如果解析的数据只包含一列,则返回一个Series。\n\n\nconverters\n规定每一列的数据类型。\n\n\nskiprows\n接受一个列表,表示跳过指定行数的数据,从头部第一行开始。\n\n\nnrows\n需要读取的行数。\n\n\nskipfooter\n接受一个列表,省略指定行数的数据,从尾部最后一行开始。\n\n\n\n示例如下所示:\nimport pandas as pd\n\n# 读取所有Sheet\ndf = pd.read_excel(\'example.xlsx\', sheet_name=None)\n\n# 读取第一个、第二个和名为"Sheet5"的工作表作为 DataFrame 的字典\ndf = pd.read_excel(\'example.xlsx\', sheet_name=[0, 1, "Sheet5"])\n获取行数和列数\nimport pandas as pd\n \ndf = pd.read_excel(\'example.xlsx\')\n# 行索引\nprint(df.index) \n# RangeIndex(start=0, stop=3747, step=1)\n\n# 输出元祖,分别为行数和列数,默认第一行是表头不算行数\nprint(df.shape) \n# (3747, 4)\n获取表头\nread_excel 默认是把 excel 的第一行当成表头。注意:如果 read_excel 的 sheet_name=None,读取的是所有 excel 的 sheet_name(key) 和 sheet_values(values) 组成的字典,df.keys() 的结果是所有 sheet_name,即名字(字典的键)。\n获取第一个 sheet\n这时候 df.keys() 和 df.columns 的结果是一样的,都是第一个 sheet 的表头。\nimport pandas as pd\n \ndf = pd.read_excel(\'input.xlsx\')\nprint(df.keys())\nprint(\'---------------\')\nprint(df.columns)\n获取所有 sheet\nimport pandas as pd\n \n# 参数为 None 代表读取所有 sheet\ndf = pd.read_excel(\'input.xlsx\',sheet_name=None)\n\n# 获取所有sheet名字, 如果read_excel参数不是None, 则df.keys()为表头\nsheet_names = list(df.keys())\nprint(sheet_names)\n参考资料\n\n老董,《pandas获取excel的行数,列数,表头,sheet,前后行等数据》,Python编程网\n《Pandas Excel读写操作详解》,C语言中文网\n《pandas.read_excel — pandas 2.1.4 documentation》,pandas documentation — pandas 2.1.4 documentation', 'bodyHTML': '

在使用 Pandas 前需要学习了解一下 Series 和 DataFrame 的基本数据结构和索引的相关概念,之后就可以练习基本的 Excel操作。Pandas 读取一个 Excel 文件后会将其转化为 DataFrame 对象,每一列或行就是一个 Series 对象。这里我们看下如何对一个 excel 进行读写,以及 Sheet、行列、表头处理的一些常用技巧。

\n

读取 Excel

\n

如果您想读取 Excel 表格中的数据,可以使用 read_excel() 方法,其语法格式如下:

\n
pd.read_excel(io, sheet_name=0, header=0, names=None, index_col=None,\n              usecols=None, squeeze=False,dtype=None, engine=None,\n              converters=None, true_values=None, false_values=None,\n              skiprows=None, nrows=None, na_values=None, parse_dates=False,\n              date_parser=None, thousands=None, comment=None, skipfooter=0,\n              convert_float=True, **kwds)\n
\n

下表对常用参数做了说明:

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
参数名称说明
io表示 Excel 文件的存储路径。
sheet_name要读取的工作表名称,默认0,即读取第一个工作表作为 DataFrame(一定要加sheet_name=None,才能读取出所有的 sheet,否则默认读取第一个 sheet)。
header指定作为列名的行,默认0,即取第一行的值为列名;若数据不包含列名,则设定 header = None。若将其设置为 header=2,则表示将前两行作为多重索引。
names一般适用于Excel缺少列名,或者需要重新定义列名的情况;names的长度必须等于Excel表格列的长度,否则会报错。
index_col用做行索引的列,可以是工作表的列名称,如 index_col = \'列名\',也可以是整数或者列表。
usecolsint或list类型,默认为None,表示需要读取所有列。
squeezeboolean,默认为False,如果解析的数据只包含一列,则返回一个Series。
converters规定每一列的数据类型。
skiprows接受一个列表,表示跳过指定行数的数据,从头部第一行开始。
nrows需要读取的行数。
skipfooter接受一个列表,省略指定行数的数据,从尾部最后一行开始。
\n

示例如下所示:

\n
import pandas as pd\n\n# 读取所有Sheet\ndf = pd.read_excel(\'example.xlsx\', sheet_name=None)\n\n# 读取第一个、第二个和名为"Sheet5"的工作表作为 DataFrame 的字典\ndf = pd.read_excel(\'example.xlsx\', sheet_name=[0, 1, "Sheet5"])
\n

获取行数和列数

\n
import pandas as pd\n \ndf = pd.read_excel(\'example.xlsx\')\n# 行索引\nprint(df.index)  \n# RangeIndex(start=0, stop=3747, step=1)\n\n# 输出元祖,分别为行数和列数,默认第一行是表头不算行数\nprint(df.shape) \n# (3747, 4)
\n

获取表头

\n

read_excel 默认是把 excel 的第一行当成表头。注意:如果 read_excelsheet_name=None,读取的是所有 excel 的 sheet_name(key) 和 sheet_values(values) 组成的字典,df.keys() 的结果是所有 sheet_name,即名字(字典的键)。

\n

获取第一个 sheet

\n

这时候 df.keys()df.columns 的结果是一样的,都是第一个 sheet 的表头。

\n
import pandas as pd\n \ndf = pd.read_excel(\'input.xlsx\')\nprint(df.keys())\nprint(\'---------------\')\nprint(df.columns)
\n

获取所有 sheet

\n
import pandas as pd\n \n# 参数为 None 代表读取所有 sheet\ndf = pd.read_excel(\'input.xlsx\',sheet_name=None)\n\n# 获取所有sheet名字, 如果read_excel参数不是None, 则df.keys()为表头\nsheet_names = list(df.keys())\nprint(sheet_names)
\n

参考资料

\n
    \n
  1. 老董,《pandas获取excel的行数,列数,表头,sheet,前后行等数据》,Python编程网
  2. \n
  3. Pandas Excel读写操作详解》,C语言中文网
  4. \n
  5. pandas.read_excel — pandas 2.1.4 documentation》,pandas documentation — pandas 2.1.4 documentation
  6. \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.2-编程'}, 'labels': {'nodes': [{'name': '1.2.3-Python'}]}, 'comments': {'nodes': []}}, {'title': '跳过任意开屏广告和内部弹窗广告', 'number': 39, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/39', 'createdAt': '2023-12-06T03:50:28Z', 'lastEditedAt': '2023-12-08T05:31:46Z', 'updatedAt': '2024-01-04T05:42:23Z', 'body': '今天去用了一下 [gkd](https://github.com/gkd-kit/gkd)—— 点击跳过任意开屏广告/点击关闭应用内部任意弹窗广告的应用,发现真不错,记录一下遇到的一些问题。\r\n\r\n\r\n\r\n具体使用步骤如下。\r\n\r\n## 1. 开启权限\r\n\r\n应用安装后,**"主页"** 页面的这几个权限都需要开启(尤其是**无障碍权限**),否则应用无法跳过广告,不起作用。 \r\n\r\ngkd-home\r\n\r\n华为鸿蒙系统怎么开启无障碍模式(也可以参考:[通过快捷方式启动无障碍功能](https://consumer.huawei.com/cn/support/content/zh-cn15849085/)): \r\n \r\n1. 打开辅助功能,进入手机设置界面,点击【辅助功能】。\r\n2. 打开无障碍,点击【无障碍】。\r\n3. 打开已安装的服务,下拉到页面底部,点击【已安装的服务】。\r\n4. 选择服务,选择要设置的服务【GKD】,点击进入。\r\n5. 打开服务开关,点击服务右侧【开关】按钮。\r\n6. 确定打开。\r\n\r\n这里会有一个问题:**鸿蒙手机无障碍打开后,点击清理后台会自动关闭**!参考:[gkd-kit/gkd#201](https://github.com/gkd-kit/gkd/issues/201)\r\n\r\n具体可以参考华为官方给出的解决方法——《[华为手机/平板无障碍中的第三方应用的服务开关自动关闭](https://consumer.huawei.com/cn/support/content/zh-cn00410039/)》。\r\n\r\n\r\n## 2. 更新订阅\r\n\r\n应用安装后,**"订阅"** 页面的本地订阅如果没有规则,则需要下拉执行更新一下即可(参考:[gkd-kit/gkd#100](https://github.com/gkd-kit/gkd/issues/100))。\r\n\r\nGKD-订阅\r\n\r\n## 3. 设置\r\n\r\n这是个人在使用时候 **"设置"** 页面的一个截图。 \r\n\r\nGKD-订阅\r\n', 'bodyText': '今天去用了一下 gkd—— 点击跳过任意开屏广告/点击关闭应用内部任意弹窗广告的应用,发现真不错,记录一下遇到的一些问题。\n\n具体使用步骤如下。\n1. 开启权限\n应用安装后,"主页" 页面的这几个权限都需要开启(尤其是无障碍权限),否则应用无法跳过广告,不起作用。\n\n华为鸿蒙系统怎么开启无障碍模式(也可以参考:通过快捷方式启动无障碍功能):\n\n打开辅助功能,进入手机设置界面,点击【辅助功能】。\n打开无障碍,点击【无障碍】。\n打开已安装的服务,下拉到页面底部,点击【已安装的服务】。\n选择服务,选择要设置的服务【GKD】,点击进入。\n打开服务开关,点击服务右侧【开关】按钮。\n确定打开。\n\n这里会有一个问题:鸿蒙手机无障碍打开后,点击清理后台会自动关闭!参考:gkd-kit/gkd#201\n具体可以参考华为官方给出的解决方法——《华为手机/平板无障碍中的第三方应用的服务开关自动关闭》。\n2. 更新订阅\n应用安装后,"订阅" 页面的本地订阅如果没有规则,则需要下拉执行更新一下即可(参考:gkd-kit/gkd#100)。\n\n3. 设置\n这是个人在使用时候 "设置" 页面的一个截图。', 'bodyHTML': '

今天去用了一下 gkd—— 点击跳过任意开屏广告/点击关闭应用内部任意弹窗广告的应用,发现真不错,记录一下遇到的一些问题。

\n\n

具体使用步骤如下。

\n

1. 开启权限

\n

应用安装后,"主页" 页面的这几个权限都需要开启(尤其是无障碍权限),否则应用无法跳过广告,不起作用。

\n

gkd-home

\n

华为鸿蒙系统怎么开启无障碍模式(也可以参考:通过快捷方式启动无障碍功能):

\n
    \n
  1. 打开辅助功能,进入手机设置界面,点击【辅助功能】。
  2. \n
  3. 打开无障碍,点击【无障碍】。
  4. \n
  5. 打开已安装的服务,下拉到页面底部,点击【已安装的服务】。
  6. \n
  7. 选择服务,选择要设置的服务【GKD】,点击进入。
  8. \n
  9. 打开服务开关,点击服务右侧【开关】按钮。
  10. \n
  11. 确定打开。
  12. \n
\n

这里会有一个问题:鸿蒙手机无障碍打开后,点击清理后台会自动关闭!参考:gkd-kit/gkd#201

\n

具体可以参考华为官方给出的解决方法——《华为手机/平板无障碍中的第三方应用的服务开关自动关闭》。

\n

2. 更新订阅

\n

应用安装后,"订阅" 页面的本地订阅如果没有规则,则需要下拉执行更新一下即可(参考:gkd-kit/gkd#100)。

\n

GKD-订阅

\n

3. 设置

\n

这是个人在使用时候 "设置" 页面的一个截图。

\n

GKD-订阅

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': [{'body': '首页的那个猫咪有意思~~', 'author': {'login': 'obaby'}}]}}, {'title': 'GitHub Discussions 使用与思考', 'number': 38, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/38', 'createdAt': '2023-12-06T01:55:19Z', 'lastEditedAt': '2024-03-18T06:25:33Z', 'updatedAt': '2024-03-18T06:25:33Z', 'body': '从2023年7月起我所有可公开的文档都保存在了 [GitHub Discussions](https://github.com/shenweiyan/Knowledge-Garden/discussions) 上,作为博客、IED 编辑器,以及评论使用,GitHub Discussions 是完全没问题的。\r\n\r\n\r\n\r\n## 开源的代名词\r\n\r\n开源已成为 GitHub 的代名词。\r\n\r\n> 当开发者谈论开源时,通常会想到 GitHub,它不仅仅是一个代码托管平台,更是一个汇聚了全球开发者的社交中心。过去,开发者发布一款软件后,都是在自己的小圈子里默默努力和交流,现在通过 GitHub 平台可以方便地与全球的开发者分享、交流和协作。贡献者在这里展示自己的才华,追随者在这里寻找强者的脚印,等待着被世人认可的时刻。\r\n\r\n## 体验与感受\r\n\r\n由于 GitHub 是直接 markdown 源码进行书写,正常的导出基本不会有格式错乱的问题,这一点非常好。不像有一些富文本的编辑器,动不动就给你增加几个换行或者空格什么的额外字符。\r\n\r\n借助 GitHub GraphQL API + Python + GitHub Actions 进行每天定时导出非常顺滑,导出来的文档可以随意折腾,自由度非常大。\r\n\r\n## 专业书籍文档\r\n\r\n今天忽然想到的一个问题,即如果作为专业性比较强的系列文档写作,如《[Hello 算法](https://www.hello-algo.com/)》 这样专业性和逻辑性非常明确的专业书籍,使用 GitHub Discussions 写作应该是有点不太合适。\r\n\r\n但又仔细想了一下,如果**只是写作**应该是没问题的 —— 我们可以用 sections 或者 categories,甚至是 tags 进行书籍分类,最后在导出的时候借助这些标签把相关的文档整合到一块,再借助 nav 梳理成大纲展现给读者阅读就可以。所以,总的来说可以用于专业书籍**写作(编辑)**,但**不太适合用于专业书籍的呈现和阅读** —— 主要是大纲和逻辑性会变得不明显。\r\n\r\n## 目录和分类标签\r\n\r\nGitHub Discussions 目前[最多支持 25 个 categories](https://github.com/orgs/community/discussions/7960),这是一个限制。因此,通过 section+category 我们在 Discussions 上最多只能实现两级的目录结构,所以对于三级和三级以上的目录结构目前暂时无能为力。\r\n\r\n因此,想到一个折中的解决方法:使用 labels 来区分第三级目录结构。\r\n```\r\n1.1-生信\r\n - 1.1.1-算法\r\n - 1.1.2-数据\r\n - 1.1.2-软件\r\n```\r\n\r\n然后,导出 Discussions 的时候需要在本地先在本地建立一个 `section+category: dictory` 一一对应的字典,最后通过这个字典把不同的讨论 md 归档至对应的目录。\r\n```\r\n1.1-生信:\r\n 1.1.1-算法: docs/cookbook/生物信息/算法\r\n 1.1.2-数据: docs/cookbook/生物信息/数据\r\n 1.1.2-软件: docs/cookbook/生物信息/软件\r\n ...\r\n```\r\n\r\n## GitHub GraphQL API\r\n\r\nGitHub Discussions 的 API 操作主要依赖 [GitHub GraphQL API](https://docs.github.com/zh/graphql/overview/about-the-graphql-api)。\r\n\r\n> ## 概述\r\n> \r\n> GraphQL 是一种用于[应用编程接口(API)](https://www.redhat.com/zh/topics/api/what-are-application-programming-interfaces)的查询语言和服务器端运行时,它可以使客户端准确地获得所需的数据,没有任何冗余。\r\n> \r\n> ## GraphQL 有什么用? \r\n> GraphQL 旨在让 API 变得快速、灵活并且为开发人员提供便利。它甚至可以部署在名为 [GraphiQL](https://github.com/graphql/graphiql) 的[集成开发环境(IDE)](https://www.redhat.com/zh/topics/middleware/what-is-ide)中。作为 [REST](https://www.redhat.com/zh/topics/integration/whats-the-difference-between-soap-rest) 的替代方案,GraphQL 允许开发人员构建相应的请求,从而通过单个 API 调用从多个数据源中提取数据。\r\n> \r\n> 此外,GraphQL 还可让 API 维护人员灵活地添加或弃用字段,而不会影响现有查询。开发人员可以使用自己喜欢的方法来构建 API,并且 GraphQL 规范将确保它们以可预测的方式在客户端发挥作用。\r\n> \r\n> From:《[什么是 GraphQL?核心概念解析](https://www.redhat.com/zh/topics/api/what-is-graphql)》- 红帽\r\n\r\n- 中文文档:https://docs.github.com/zh/graphql/guides/introduction-to-graphql\r\n- 在线使用:https://docs.github.com/en/graphql/overview/explorer\r\n\r\n### 获取 discussions 主要信息\r\n```\r\n{\r\n repository(owner: "shenweiyan", name: "Knowledge-Garden") {\r\n discussions(orderBy: {field: CREATED_AT, direction: DESC}, categoryId: null, first: 5) {\r\n nodes {\r\n title\r\n number\r\n url\r\n createdAt\r\n lastEditedAt\r\n updatedAt\r\n body\r\n bodyText\r\n bodyHTML\r\n author {\r\n login\r\n }\r\n category {\r\n name\r\n }\r\n labels(first: 100) {\r\n nodes {\r\n name\r\n }\r\n }\r\n comments(first: 10) {\r\n nodes {\r\n body\r\n author {\r\n login\r\n }\r\n }\r\n }\r\n }\r\n pageInfo {\r\n hasNextPage\r\n endCursor\r\n }\r\n }\r\n }\r\n}\r\n```\r\n\r\n\r\n### 获取 discussions categoryId\r\n\r\n参考:《[how to get github discussions categoryId](https://qiita.com/shooter/items/d59fbb43d0f118c95092)》\r\n\r\n```\r\n{\r\n repository(owner: "shenweiyan", name: "Knowledge-Garden") {\r\n id\r\n name\r\n discussionCategories(first: 30) {\r\n nodes {\r\n id\r\n name\r\n }\r\n }\r\n }\r\n}\r\n```\r\n\r\n### 其他的一些问题\r\n\r\n目前,通过 GitHub GraphQL API 暂时无法获取 Sections 的信息。\r\n\r\n## 简单的总结\r\n\r\n拥抱 GitHub Discussions 的一个前提是你可以随时登录 GitHub,如果你已经解决了这个问题,也想着像我一样 Using Github discussions as your blog engine,那么你可以参考一下我的 [shenweiyan/Knowledge-Garden](https://github.com/shenweiyan/Knowledge-Garden/) 仓库。', 'bodyText': '从2023年7月起我所有可公开的文档都保存在了 GitHub Discussions 上,作为博客、IED 编辑器,以及评论使用,GitHub Discussions 是完全没问题的。\n\n开源的代名词\n开源已成为 GitHub 的代名词。\n\n当开发者谈论开源时,通常会想到 GitHub,它不仅仅是一个代码托管平台,更是一个汇聚了全球开发者的社交中心。过去,开发者发布一款软件后,都是在自己的小圈子里默默努力和交流,现在通过 GitHub 平台可以方便地与全球的开发者分享、交流和协作。贡献者在这里展示自己的才华,追随者在这里寻找强者的脚印,等待着被世人认可的时刻。\n\n体验与感受\n由于 GitHub 是直接 markdown 源码进行书写,正常的导出基本不会有格式错乱的问题,这一点非常好。不像有一些富文本的编辑器,动不动就给你增加几个换行或者空格什么的额外字符。\n借助 GitHub GraphQL API + Python + GitHub Actions 进行每天定时导出非常顺滑,导出来的文档可以随意折腾,自由度非常大。\n专业书籍文档\n今天忽然想到的一个问题,即如果作为专业性比较强的系列文档写作,如《Hello 算法》 这样专业性和逻辑性非常明确的专业书籍,使用 GitHub Discussions 写作应该是有点不太合适。\n但又仔细想了一下,如果只是写作应该是没问题的 —— 我们可以用 sections 或者 categories,甚至是 tags 进行书籍分类,最后在导出的时候借助这些标签把相关的文档整合到一块,再借助 nav 梳理成大纲展现给读者阅读就可以。所以,总的来说可以用于专业书籍写作(编辑),但不太适合用于专业书籍的呈现和阅读 —— 主要是大纲和逻辑性会变得不明显。\n目录和分类标签\nGitHub Discussions 目前最多支持 25 个 categories,这是一个限制。因此,通过 section+category 我们在 Discussions 上最多只能实现两级的目录结构,所以对于三级和三级以上的目录结构目前暂时无能为力。\n因此,想到一个折中的解决方法:使用 labels 来区分第三级目录结构。\n1.1-生信\n - 1.1.1-算法\n - 1.1.2-数据\n - 1.1.2-软件\n\n然后,导出 Discussions 的时候需要在本地先在本地建立一个 section+category: dictory 一一对应的字典,最后通过这个字典把不同的讨论 md 归档至对应的目录。\n1.1-生信:\n 1.1.1-算法: docs/cookbook/生物信息/算法\n 1.1.2-数据: docs/cookbook/生物信息/数据\n 1.1.2-软件: docs/cookbook/生物信息/软件\n ...\n\nGitHub GraphQL API\nGitHub Discussions 的 API 操作主要依赖 GitHub GraphQL API。\n\n概述\nGraphQL 是一种用于应用编程接口(API)的查询语言和服务器端运行时,它可以使客户端准确地获得所需的数据,没有任何冗余。\nGraphQL 有什么用?\nGraphQL 旨在让 API 变得快速、灵活并且为开发人员提供便利。它甚至可以部署在名为 GraphiQL 的集成开发环境(IDE)中。作为 REST 的替代方案,GraphQL 允许开发人员构建相应的请求,从而通过单个 API 调用从多个数据源中提取数据。\n此外,GraphQL 还可让 API 维护人员灵活地添加或弃用字段,而不会影响现有查询。开发人员可以使用自己喜欢的方法来构建 API,并且 GraphQL 规范将确保它们以可预测的方式在客户端发挥作用。\nFrom:《什么是 GraphQL?核心概念解析》- 红帽\n\n\n中文文档:https://docs.github.com/zh/graphql/guides/introduction-to-graphql\n在线使用:https://docs.github.com/en/graphql/overview/explorer\n\n获取 discussions 主要信息\n{\n repository(owner: "shenweiyan", name: "Knowledge-Garden") {\n discussions(orderBy: {field: CREATED_AT, direction: DESC}, categoryId: null, first: 5) {\n nodes {\n title\n number\n url\n createdAt\n lastEditedAt\n updatedAt\n body\n bodyText\n bodyHTML\n author {\n login\n }\n category {\n name\n }\n labels(first: 100) {\n nodes {\n name\n }\n }\n comments(first: 10) {\n nodes {\n body\n author {\n login\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n }\n}\n\n获取 discussions categoryId\n参考:《how to get github discussions categoryId》\n{\n repository(owner: "shenweiyan", name: "Knowledge-Garden") {\n id\n name\n discussionCategories(first: 30) {\n nodes {\n id\n name\n }\n }\n }\n}\n\n其他的一些问题\n目前,通过 GitHub GraphQL API 暂时无法获取 Sections 的信息。\n简单的总结\n拥抱 GitHub Discussions 的一个前提是你可以随时登录 GitHub,如果你已经解决了这个问题,也想着像我一样 Using Github discussions as your blog engine,那么你可以参考一下我的 shenweiyan/Knowledge-Garden 仓库。', 'bodyHTML': '

从2023年7月起我所有可公开的文档都保存在了 GitHub Discussions 上,作为博客、IED 编辑器,以及评论使用,GitHub Discussions 是完全没问题的。

\n\n

开源的代名词

\n

开源已成为 GitHub 的代名词。

\n
\n

当开发者谈论开源时,通常会想到 GitHub,它不仅仅是一个代码托管平台,更是一个汇聚了全球开发者的社交中心。过去,开发者发布一款软件后,都是在自己的小圈子里默默努力和交流,现在通过 GitHub 平台可以方便地与全球的开发者分享、交流和协作。贡献者在这里展示自己的才华,追随者在这里寻找强者的脚印,等待着被世人认可的时刻。

\n
\n

体验与感受

\n

由于 GitHub 是直接 markdown 源码进行书写,正常的导出基本不会有格式错乱的问题,这一点非常好。不像有一些富文本的编辑器,动不动就给你增加几个换行或者空格什么的额外字符。

\n

借助 GitHub GraphQL API + Python + GitHub Actions 进行每天定时导出非常顺滑,导出来的文档可以随意折腾,自由度非常大。

\n

专业书籍文档

\n

今天忽然想到的一个问题,即如果作为专业性比较强的系列文档写作,如《Hello 算法》 这样专业性和逻辑性非常明确的专业书籍,使用 GitHub Discussions 写作应该是有点不太合适。

\n

但又仔细想了一下,如果只是写作应该是没问题的 —— 我们可以用 sections 或者 categories,甚至是 tags 进行书籍分类,最后在导出的时候借助这些标签把相关的文档整合到一块,再借助 nav 梳理成大纲展现给读者阅读就可以。所以,总的来说可以用于专业书籍写作(编辑),但不太适合用于专业书籍的呈现和阅读 —— 主要是大纲和逻辑性会变得不明显。

\n

目录和分类标签

\n

GitHub Discussions 目前最多支持 25 个 categories,这是一个限制。因此,通过 section+category 我们在 Discussions 上最多只能实现两级的目录结构,所以对于三级和三级以上的目录结构目前暂时无能为力。

\n

因此,想到一个折中的解决方法:使用 labels 来区分第三级目录结构。

\n
1.1-生信\n  - 1.1.1-算法\n  - 1.1.2-数据\n  - 1.1.2-软件\n
\n

然后,导出 Discussions 的时候需要在本地先在本地建立一个 section+category: dictory 一一对应的字典,最后通过这个字典把不同的讨论 md 归档至对应的目录。

\n
1.1-生信:\n    1.1.1-算法: docs/cookbook/生物信息/算法\n    1.1.2-数据: docs/cookbook/生物信息/数据\n    1.1.2-软件: docs/cookbook/生物信息/软件\n    ...\n
\n

GitHub GraphQL API

\n

GitHub Discussions 的 API 操作主要依赖 GitHub GraphQL API

\n
\n

概述

\n

GraphQL 是一种用于应用编程接口(API)的查询语言和服务器端运行时,它可以使客户端准确地获得所需的数据,没有任何冗余。

\n

GraphQL 有什么用?

\n

GraphQL 旨在让 API 变得快速、灵活并且为开发人员提供便利。它甚至可以部署在名为 GraphiQL集成开发环境(IDE)中。作为 REST 的替代方案,GraphQL 允许开发人员构建相应的请求,从而通过单个 API 调用从多个数据源中提取数据。

\n

此外,GraphQL 还可让 API 维护人员灵活地添加或弃用字段,而不会影响现有查询。开发人员可以使用自己喜欢的方法来构建 API,并且 GraphQL 规范将确保它们以可预测的方式在客户端发挥作用。

\n

From:《什么是 GraphQL?核心概念解析》- 红帽

\n
\n\n

获取 discussions 主要信息

\n
{\n  repository(owner: "shenweiyan", name: "Knowledge-Garden") {\n    discussions(orderBy: {field: CREATED_AT, direction: DESC}, categoryId: null, first: 5) {\n      nodes {\n        title\n        number\n        url\n        createdAt\n        lastEditedAt\n        updatedAt\n        body\n        bodyText\n        bodyHTML\n        author {\n          login\n        }\n        category {\n          name\n        }\n        labels(first: 100) {\n          nodes {\n            name\n          }\n        }\n        comments(first: 10) {\n          nodes {\n            body\n            author {\n              login\n            }\n          }\n        }\n      }\n      pageInfo {\n        hasNextPage\n        endCursor\n      }\n    }\n  }\n}\n
\n

获取 discussions categoryId

\n

参考:《how to get github discussions categoryId

\n
{\n  repository(owner: "shenweiyan", name: "Knowledge-Garden") {\n    id\n    name\n    discussionCategories(first: 30) {\n      nodes {\n        id\n        name\n      }\n    }\n  }\n}\n
\n

其他的一些问题

\n

目前,通过 GitHub GraphQL API 暂时无法获取 Sections 的信息。

\n

简单的总结

\n

拥抱 GitHub Discussions 的一个前提是你可以随时登录 GitHub,如果你已经解决了这个问题,也想着像我一样 Using Github discussions as your blog engine,那么你可以参考一下我的 shenweiyan/Knowledge-Garden 仓库。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': [{'name': '公众号'}]}, 'comments': {'nodes': []}}, {'title': 'MkDocs Material 安装部署和使用', 'number': 37, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/37', 'createdAt': '2023-12-06T01:28:00Z', 'lastEditedAt': '2023-12-11T02:08:45Z', 'updatedAt': '2024-01-04T05:42:38Z', 'body': 'MkDocs 是一个快速、简单、华丽的静态网站生成器,适用于构建项目文档。文档源文件以 Markdown 编写,并使用一个 YAML 文件来进行配置。[Material for MkDocs](https://squidfunk.github.io/mkdocs-material/) 是 [MkDocs](https://www.mkdocs.org/) 的一个主题配置,更加简洁美观,更新和维护也更加及时和频繁,且社区也更加活跃。\r\n\r\n\r\n\r\n## 安装\r\n\r\n主要使用的一些软件包以及模块 (requirements.txt) 如下:\r\n```\r\nmkdocs==1.5.3\r\nmkdocs-material\r\nmkdocs-rss-plugin\r\nmkdocs-git-revision-date-plugin\r\nmkdocs-include-dir-to-nav==1.2.0\r\nmkdocs-glightbox\r\njieba\r\n```\r\n\r\n```\r\npip3 install -r requirements.txt\r\n```\r\n\r\n查看 `mkdocs-material`, `mkdocs` 的版本:\r\n```python\r\n$ mkdocs --version\r\nmkdocs, version 1.5.3 from /usr/local/software/python-3.9.18/lib/python3.9/site-packages/mkdocs (Python 3.9)\r\n\r\n$ pip3 show mkdocs-material\r\nName: mkdocs-material\r\nVersion: 9.4.4\r\nSummary: Documentation that simply works\r\nHome-page: \r\nAuthor: \r\nAuthor-email: Martin Donath \r\nLicense: \r\nLocation: /usr/local/software/python-3.9.18/lib/python3.9/site-packages\r\nRequires: babel, colorama, jinja2, markdown, mkdocs, mkdocs-material-extensions, paginate, pygments, pymdown-extensions, regex, requests\r\nRequired-by:\r\n```\r\n\r\n## 使用\r\n\r\n本地预览:\r\n```\r\n$ mkdocs serve -a 0.0.0.0:8000\r\n```\r\n\r\n## 问题与解决\r\n\r\n1. Pagination 分页与 `git-revision-date` 冲突,导致无法构建 - 参考 [mkdocs-material/discussions/6156](https://github.com/squidfunk/mkdocs-material/discussions/6156)\r\n2. [Support Markdown in the copyright string #5134](https://github.com/squidfunk/mkdocs-material/issues/5134)\r\n3. [如何在 MkDocs 的版权部分自动添加年份 - squidfunk/mkdocs-material#4969](https://github.com/squidfunk/mkdocs-material/discussions/4969)\r\n4. [如何定制博客插件的归档页面 - squidfunk/mkdocs-material#6324](https://github.com/squidfunk/mkdocs-material/discussions/6324)\r\n\r\n## 期待的功能\r\n\r\n这是一个个人非常期待的功能,大部分目前已经可以在 [Insiders](https://squidfunk.github.io/mkdocs-material/insiders/) 版本中使用,社区公开的版本尚无法使用。\r\n\r\n- 博客插件的自定义归档、目录页面每页文档数 - [squidfunk/mkdocs-material#6383](https://github.com/squidfunk/mkdocs-material/issues/6383)\r\n- 内置隐私插件(方便内网/国内部署加速访问)- [Built-in privacy plugin - Material for MkDocs](https://squidfunk.github.io/mkdocs-material/plugins/privacy/) \r\n 内置隐私插件(privacy plugin) 在 [9.5.0](https://github.com/squidfunk/mkdocs-material/releases/tag/9.5.0) 中已经k可以正常使用了,下一个值得期待的就是该插件的 [`assets_exclude`](https://squidfunk.github.io/mkdocs-material/plugins/privacy/#config.assets_exclude) 功能!', 'bodyText': 'MkDocs 是一个快速、简单、华丽的静态网站生成器,适用于构建项目文档。文档源文件以 Markdown 编写,并使用一个 YAML 文件来进行配置。Material for MkDocs 是 MkDocs 的一个主题配置,更加简洁美观,更新和维护也更加及时和频繁,且社区也更加活跃。\n\n安装\n主要使用的一些软件包以及模块 (requirements.txt) 如下:\nmkdocs==1.5.3\nmkdocs-material\nmkdocs-rss-plugin\nmkdocs-git-revision-date-plugin\nmkdocs-include-dir-to-nav==1.2.0\nmkdocs-glightbox\njieba\n\npip3 install -r requirements.txt\n\n查看 mkdocs-material, mkdocs 的版本:\n$ mkdocs --version\nmkdocs, version 1.5.3 from /usr/local/software/python-3.9.18/lib/python3.9/site-packages/mkdocs (Python 3.9)\n\n$ pip3 show mkdocs-material\nName: mkdocs-material\nVersion: 9.4.4\nSummary: Documentation that simply works\nHome-page: \nAuthor: \nAuthor-email: Martin Donath \nLicense: \nLocation: /usr/local/software/python-3.9.18/lib/python3.9/site-packages\nRequires: babel, colorama, jinja2, markdown, mkdocs, mkdocs-material-extensions, paginate, pygments, pymdown-extensions, regex, requests\nRequired-by:\n使用\n本地预览:\n$ mkdocs serve -a 0.0.0.0:8000\n\n问题与解决\n\nPagination 分页与 git-revision-date 冲突,导致无法构建 - 参考 mkdocs-material/discussions/6156\nSupport Markdown in the copyright string #5134\n如何在 MkDocs 的版权部分自动添加年份 - squidfunk/mkdocs-material#4969\n如何定制博客插件的归档页面 - squidfunk/mkdocs-material#6324\n\n期待的功能\n这是一个个人非常期待的功能,大部分目前已经可以在 Insiders 版本中使用,社区公开的版本尚无法使用。\n\n博客插件的自定义归档、目录页面每页文档数 - squidfunk/mkdocs-material#6383\n内置隐私插件(方便内网/国内部署加速访问)- Built-in privacy plugin - Material for MkDocs\n内置隐私插件(privacy plugin) 在 9.5.0 中已经k可以正常使用了,下一个值得期待的就是该插件的 assets_exclude 功能!', 'bodyHTML': '

MkDocs 是一个快速、简单、华丽的静态网站生成器,适用于构建项目文档。文档源文件以 Markdown 编写,并使用一个 YAML 文件来进行配置。Material for MkDocsMkDocs 的一个主题配置,更加简洁美观,更新和维护也更加及时和频繁,且社区也更加活跃。

\n\n

安装

\n

主要使用的一些软件包以及模块 (requirements.txt) 如下:

\n
mkdocs==1.5.3\nmkdocs-material\nmkdocs-rss-plugin\nmkdocs-git-revision-date-plugin\nmkdocs-include-dir-to-nav==1.2.0\nmkdocs-glightbox\njieba\n
\n
pip3 install -r requirements.txt\n
\n

查看 mkdocs-material, mkdocs 的版本:

\n
$ mkdocs --version\nmkdocs, version 1.5.3 from /usr/local/software/python-3.9.18/lib/python3.9/site-packages/mkdocs (Python 3.9)\n\n$ pip3 show mkdocs-material\nName: mkdocs-material\nVersion: 9.4.4\nSummary: Documentation that simply works\nHome-page: \nAuthor: \nAuthor-email: Martin Donath <martin.donath@squidfunk.com>\nLicense: \nLocation: /usr/local/software/python-3.9.18/lib/python3.9/site-packages\nRequires: babel, colorama, jinja2, markdown, mkdocs, mkdocs-material-extensions, paginate, pygments, pymdown-extensions, regex, requests\nRequired-by:
\n

使用

\n

本地预览:

\n
$ mkdocs serve -a 0.0.0.0:8000\n
\n

问题与解决

\n
    \n
  1. Pagination 分页与 git-revision-date 冲突,导致无法构建 - 参考 mkdocs-material/discussions/6156
  2. \n
  3. Support Markdown in the copyright string #5134
  4. \n
  5. 如何在 MkDocs 的版权部分自动添加年份 - squidfunk/mkdocs-material#4969
  6. \n
  7. 如何定制博客插件的归档页面 - squidfunk/mkdocs-material#6324
  8. \n
\n

期待的功能

\n

这是一个个人非常期待的功能,大部分目前已经可以在 Insiders 版本中使用,社区公开的版本尚无法使用。

\n', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '为 Material for MkDocs 增加博客插件', 'number': 36, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/36', 'createdAt': '2023-12-06T01:26:26Z', 'lastEditedAt': None, 'updatedAt': '2024-01-04T05:43:47Z', 'body': 'Material for MkDocs 从 9.2.0 开始内置博客插件,内置博客插件添加了对从帖子文件夹构建博客的支持,这些帖子带有日期和其他结构化数据注释。\r\n\r\n\r\n\r\nMaterial for MkDocs makes it very easy to build a blog, either as a sidecar to your documentation or standalone. Focus on your content while the engine does all the heavy lifting, automatically generating archive and category indexes, post slugs, configurable pagination and more.\r\n\r\nMaterial for MkDocs 使构建博客变得非常容易,无论是作为文档的附属工具还是独立的博客。专注于您的内容,而引擎会完成所有繁重的工作,自动生成存档和类别索引、帖子段、可配置的分页等等。\r\n\r\n存在的一些问题和使用体验:\r\n\r\n1. 在 Markdown 中使用 `` 的写法分割 description 和全文,总感觉有点别扭;\r\n2. Pagination 分页与 `git-revision-date` 冲突,会引发构建错误 - 参考 [mkdocs-material/discussions#6156](https://github.com/squidfunk/mkdocs-material/discussions/6156)\r\n\r\n## 写博客\r\n\r\n有感于 Material for MkDocs 的博客结构,现在基本上可以实现使用 Discussions 进行 MkDocs blog 编辑与写作 —— 在 Discussions 上写完文章,借助第三方工具或者 GitHub Actions 导出为 Markdown 文件,保存到 `docs/blog/posts` 就可以啦!\r\n\r\n## 加评论\r\n\r\n借助 [giscus](https://giscus.app/zh-CN),可以非常方便在文章页中插入指定的 discussions —— 在导出 discussions 的时候,在文章尾部增加类似以下 JavaScript 即可:\r\n```javascript\r\n\r\n```\r\n\r\n## 自定义归档页面\r\n\r\n[mkdocs-material](https://github.com/squidfunk/mkdocs-material) 的归档页面跟博客 index 主页面基本是一个样,如果想要列表式的自定义,可以参考 [squidfunk/mkdocs-material#6324](https://github.com/squidfunk/mkdocs-material/discussions/6324) 和 [squidfunk/mkdocs-material#6383](https://github.com/squidfunk/mkdocs-material/issues/6383)。\r\n\r\n官方在 [8ecee7b](https://github.com/squidfunk/mkdocs-material-insiders/commit/8ecee7b9dbdc5b2a0befd043a048ad25d56c784f) (Insiders) 中增加了几个个性化的新设置参数: \r\n \r\n- [`archive_pagination`](https://squidfunk.github.io/mkdocs-material/plugins/blog/#config.archive_pagination)\r\n- [`archive_pagination_per_page`](https://squidfunk.github.io/mkdocs-material/plugins/blog/#config.archive_pagination_per_page)\r\n- [`categories_pagination`](https://squidfunk.github.io/mkdocs-material/plugins/blog/#config.categories_pagination)\r\n- [`categories_pagination_per_page`](https://squidfunk.github.io/mkdocs-material/plugins/blog/#config.categories_pagination_per_page)\r\n\r\n所以,等开放给公用版本使用后,可以再好好折腾一下。\r\n', 'bodyText': 'Material for MkDocs 从 9.2.0 开始内置博客插件,内置博客插件添加了对从帖子文件夹构建博客的支持,这些帖子带有日期和其他结构化数据注释。\n\nMaterial for MkDocs makes it very easy to build a blog, either as a sidecar to your documentation or standalone. Focus on your content while the engine does all the heavy lifting, automatically generating archive and category indexes, post slugs, configurable pagination and more.\nMaterial for MkDocs 使构建博客变得非常容易,无论是作为文档的附属工具还是独立的博客。专注于您的内容,而引擎会完成所有繁重的工作,自动生成存档和类别索引、帖子段、可配置的分页等等。\n存在的一些问题和使用体验:\n\n在 Markdown 中使用 的写法分割 description 和全文,总感觉有点别扭;\nPagination 分页与 git-revision-date 冲突,会引发构建错误 - 参考 mkdocs-material/discussions#6156\n\n写博客\n有感于 Material for MkDocs 的博客结构,现在基本上可以实现使用 Discussions 进行 MkDocs blog 编辑与写作 —— 在 Discussions 上写完文章,借助第三方工具或者 GitHub Actions 导出为 Markdown 文件,保存到 docs/blog/posts 就可以啦!\n加评论\n借助 giscus,可以非常方便在文章页中插入指定的 discussions —— 在导出 discussions 的时候,在文章尾部增加类似以下 JavaScript 即可:\n\n自定义归档页面\nmkdocs-material 的归档页面跟博客 index 主页面基本是一个样,如果想要列表式的自定义,可以参考 squidfunk/mkdocs-material#6324 和 squidfunk/mkdocs-material#6383。\n官方在 8ecee7b (Insiders) 中增加了几个个性化的新设置参数:\n\narchive_pagination\narchive_pagination_per_page\ncategories_pagination\ncategories_pagination_per_page\n\n所以,等开放给公用版本使用后,可以再好好折腾一下。', 'bodyHTML': '

Material for MkDocs 从 9.2.0 开始内置博客插件,内置博客插件添加了对从帖子文件夹构建博客的支持,这些帖子带有日期和其他结构化数据注释。

\n\n

Material for MkDocs makes it very easy to build a blog, either as a sidecar to your documentation or standalone. Focus on your content while the engine does all the heavy lifting, automatically generating archive and category indexes, post slugs, configurable pagination and more.

\n

Material for MkDocs 使构建博客变得非常容易,无论是作为文档的附属工具还是独立的博客。专注于您的内容,而引擎会完成所有繁重的工作,自动生成存档和类别索引、帖子段、可配置的分页等等。

\n

存在的一些问题和使用体验:

\n
    \n
  1. 在 Markdown 中使用 <!-- more --> 的写法分割 description 和全文,总感觉有点别扭;
  2. \n
  3. Pagination 分页与 git-revision-date 冲突,会引发构建错误 - 参考 mkdocs-material/discussions#6156
  4. \n
\n

写博客

\n

有感于 Material for MkDocs 的博客结构,现在基本上可以实现使用 Discussions 进行 MkDocs blog 编辑与写作 —— 在 Discussions 上写完文章,借助第三方工具或者 GitHub Actions 导出为 Markdown 文件,保存到 docs/blog/posts 就可以啦!

\n

加评论

\n

借助 giscus,可以非常方便在文章页中插入指定的 discussions —— 在导出 discussions 的时候,在文章尾部增加类似以下 JavaScript 即可:

\n
<script src="https://giscus.app/client.js"\n        data-repo="shenweiyan/Knowledge-Garden"\n        data-repo-id="R_kgDOKgxWlg"\n        data-mapping="number"\n        data-term="4"\n        data-reactions-enabled="1"\n        data-emit-metadata="0"\n        data-input-position="bottom"\n        data-theme="light"\n        data-lang="zh-CN"\n        crossorigin="anonymous"\n        async>\n</script>
\n

自定义归档页面

\n

mkdocs-material 的归档页面跟博客 index 主页面基本是一个样,如果想要列表式的自定义,可以参考 squidfunk/mkdocs-material#6324squidfunk/mkdocs-material#6383

\n

官方在 8ecee7b (Insiders) 中增加了几个个性化的新设置参数:

\n\n

所以,等开放给公用版本使用后,可以再好好折腾一下。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '备用讨论', 'number': 35, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/35', 'createdAt': '2023-12-06T01:22:49Z', 'lastEditedAt': '2024-03-21T03:19:44Z', 'updatedAt': '2024-03-21T03:19:46Z', 'body': '备用讨论', 'bodyText': '备用讨论', 'bodyHTML': '

备用讨论

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '0.1-站点'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '博客与写作的一些思考', 'number': 34, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/34', 'createdAt': '2023-12-05T06:32:32Z', 'lastEditedAt': '2023-12-08T05:32:46Z', 'updatedAt': '2023-12-11T08:30:56Z', 'body': '关于写作原本的想法,只是想写点自己在学习、工作、生活上的一些心得和体会,把一些知识点记录下来。\r\n\r\n留言的初衷是,希望自己写下来的东西能够有人一起探讨。哪怕你把我的观点批评得一无是处也可以,哪怕你说我的句子狗屁不通也没关系,只要有评判,我相信总有一天我会变得更好。\r\n\r\n\r\n\r\n写作也好留言也罢,博客也只是一种实现的载体,语雀、博客园也是同样的道理,平台的选择虽然重要,但根本还是在于内容。\r\n\r\n每次看到人家一些内容翔实,界面优雅的博客,总要跟自己说,要忍住再去折腾博客的冲动,什么 UI,什么 CSS/HTML,都是浮云,内容才是核心,老老实实回归最简单的 Issues 和 Discussions 已经足够了。另外,需要知道的是,博客其实就是写给自己看的,什么 SEO 流量、关注度、知名度还是需要一颗随缘的心态。\r\n\r\n使用 Issues 当作博客也是挺不错的~\r\n\r\n- \r\n- \r\n- \r\n\r\n关于部分平台商业化的写作,有两点自认为讲的挺好: \r\n\r\n- 商业化已经改变了写作的初衷。 \r\n- 当写文章变成盈利的手段,那么,写出来的东西是没有灵魂的。', 'bodyText': '关于写作原本的想法,只是想写点自己在学习、工作、生活上的一些心得和体会,把一些知识点记录下来。\n留言的初衷是,希望自己写下来的东西能够有人一起探讨。哪怕你把我的观点批评得一无是处也可以,哪怕你说我的句子狗屁不通也没关系,只要有评判,我相信总有一天我会变得更好。\n\n写作也好留言也罢,博客也只是一种实现的载体,语雀、博客园也是同样的道理,平台的选择虽然重要,但根本还是在于内容。\n每次看到人家一些内容翔实,界面优雅的博客,总要跟自己说,要忍住再去折腾博客的冲动,什么 UI,什么 CSS/HTML,都是浮云,内容才是核心,老老实实回归最简单的 Issues 和 Discussions 已经足够了。另外,需要知道的是,博客其实就是写给自己看的,什么 SEO 流量、关注度、知名度还是需要一颗随缘的心态。\n使用 Issues 当作博客也是挺不错的~\n\nhttps://github.com/Meekdai/Gmeek\nhttps://github.com/yihong0618/gitblog\nhttps://github.com/yutingzhao1991/github-blogs-collector\n\n关于部分平台商业化的写作,有两点自认为讲的挺好:\n\n商业化已经改变了写作的初衷。\n当写文章变成盈利的手段,那么,写出来的东西是没有灵魂的。', 'bodyHTML': '

关于写作原本的想法,只是想写点自己在学习、工作、生活上的一些心得和体会,把一些知识点记录下来。

\n

留言的初衷是,希望自己写下来的东西能够有人一起探讨。哪怕你把我的观点批评得一无是处也可以,哪怕你说我的句子狗屁不通也没关系,只要有评判,我相信总有一天我会变得更好。

\n\n

写作也好留言也罢,博客也只是一种实现的载体,语雀、博客园也是同样的道理,平台的选择虽然重要,但根本还是在于内容。

\n

每次看到人家一些内容翔实,界面优雅的博客,总要跟自己说,要忍住再去折腾博客的冲动,什么 UI,什么 CSS/HTML,都是浮云,内容才是核心,老老实实回归最简单的 Issues 和 Discussions 已经足够了。另外,需要知道的是,博客其实就是写给自己看的,什么 SEO 流量、关注度、知名度还是需要一颗随缘的心态。

\n

使用 Issues 当作博客也是挺不错的~

\n\n

关于部分平台商业化的写作,有两点自认为讲的挺好:

\n
    \n
  • 商业化已经改变了写作的初衷。
  • \n
  • 当写文章变成盈利的手段,那么,写出来的东西是没有灵魂的。
  • \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': [{'name': '博客'}]}, 'comments': {'nodes': [{'body': '自娱自乐的小树洞,我也是', 'author': {'login': 'obaby'}}]}}, {'title': '使用 meta 实现页面的定时刷新或跳转', 'number': 33, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/33', 'createdAt': '2023-12-05T03:25:01Z', 'lastEditedAt': '2024-02-29T01:26:02Z', 'updatedAt': '2024-02-29T01:26:02Z', 'body': '这个方法最开始是在 [Linlin Yan (颜林林)](https://github.com/yanlinlin82) 的 GitHub Pages 上第一次看到。后来,随着自己也用上了,就开始有了更深一些的认识。\r\n\r\n\r\n\r\n## 跳转域名\r\n\r\n在 [yanlinlin82/yanlinlin82.github.io](https://github.com/yanlinlin82/yanlinlin82.github.io/tree/master) 看到一个通过 可以直接重定向到 的用法 —— 只需要把 `index.html` 写成这样就可以:\r\n```html\r\n\r\n\r\n \r\n \r\n\r\n```\r\n\r\n## 页面定时跳转与刷新\r\n\r\n这部分的内容主要来源自:《[小tip: 使用meta实现页面的定时刷新或跳转](https://www.zhangxinxu.com/wordpress/2015/03/meta-http-equiv-refresh-content/)》。\r\n\r\n> ### meta 源信息功能之页面定时跳转与刷新\r\n> \r\n> 几乎所有的网页头部都有``源信息。除了我们常用的定义编码、关键字(name=”keywords”)、描述(name=”description”)(for SEO),还可以定义视区大小、缩放比例等(for 移动端),如下:\r\n> \r\n> ```\r\n> \r\n> ```\r\n> \r\n> 以及,定义网页的过期时间,Cookie 的过期时间等等。\r\n> \r\n> 文本要介绍的内容,科科,跟上面都没关系。哦,抱歉,都有关系,只是名称我故意没提到。主角嘛,总要最后闪亮登场!\r\n> \r\n> 就是我们网页平时跳转,还可以使用 `` 实现,下面几个典型代码示例: \r\n> ```html \r\n> \r\n> ```\r\n> 这个表示当前页面每5秒钟刷一下,刷一下~\r\n> \r\n> ```html\r\n> \r\n> ```\r\n> 这个表示当前页面2秒后跳到首页~ \r\n> \r\n> ```html\r\n> \r\n> ```\r\n> 页面直接跳转到腾讯网~\r\n> \r\n> 所以,当我们下次遇到“登录成功,正在跳转到您之前访问页面……”的时候,可以使用``的这个`refresh`刷新,跳转功能,可以说是成本最低的。 \r\n> \r\n> 您可以狠狠地点击这里:[meta与当前页面定时刷新Demo](http://www.zhangxinxu.com/study/201503/meta-fresh-content.html) \r\n> ![meta-refresh](https://shub.weiyan.tech/kgarden/2024/01/meta-refresh.37epe9yaam80.png)\r\n> \r\n> 上面 Demo 效果就是上面第1个示例代码效果。 \r\n> \r\n> 根据我的测试,此特性包括IE7在内的浏览器都是支持的。 \r\n> \r\n> ### 问题来了:为何 meta 跳转不火呢?\r\n> \r\n> 大家可以看到,`meta` 跳转,使用方便,不用写 JS,不用会后台代码,定时跳转刷新什么的玩得照样很溜,而且兼容性好,为啥总感觉不温不火,很少看见有人提及呢? \r\n> \r\n> 新晋的小伙伴不知有没有听过这么一个词,叫做“万恶的IE6年代”。\r\n> \r\n> 据说,当年,这一批老旧的浏览器,问题很多,其中就有对`meta` 两个小小的不友好。我也是听说,不一定准确。坊间是这么传闻的: \r\n> \r\n> - 时间设为0的跳转,有时候页面会闪一下; \r\n> - 跳转到其他页面,浏览器后退按钮是不能用的; \r\n> \r\n> 但是啊,现在是什么年代啊,监狱风云都拍到第二季了,这些老问题,我觉得就可以忽略不计了。 \r\n> \r\n> 不妨大胆试试 `meta` 跳转,好好利用下浏览器的原生特性,说不定就会发现比什么 JS 跳转之流用得更开心。\r\n\r\n所以,在文章的最后有一个小想法 —— 我们是不是也可以利用这个方法实现无数个链接 301 重定向( URL 转发),再也不需要担心是否需要主机+Nginx 之类!\r\n', 'bodyText': '这个方法最开始是在 Linlin Yan (颜林林) 的 GitHub Pages 上第一次看到。后来,随着自己也用上了,就开始有了更深一些的认识。\n\n跳转域名\n在 yanlinlin82/yanlinlin82.github.io 看到一个通过 https://yanlinlin82.github.io 可以直接重定向到 https://yanlinlin.cn/ 的用法 —— 只需要把 index.html 写成这样就可以:\n\n\n \n \n\n页面定时跳转与刷新\n这部分的内容主要来源自:《小tip: 使用meta实现页面的定时刷新或跳转》。\n\nmeta 源信息功能之页面定时跳转与刷新\n几乎所有的网页头部都有源信息。除了我们常用的定义编码、关键字(name=”keywords”)、描述(name=”description”)(for SEO),还可以定义视区大小、缩放比例等(for 移动端),如下:\n\n\n以及,定义网页的过期时间,Cookie 的过期时间等等。\n文本要介绍的内容,科科,跟上面都没关系。哦,抱歉,都有关系,只是名称我故意没提到。主角嘛,总要最后闪亮登场!\n就是我们网页平时跳转,还可以使用 实现,下面几个典型代码示例:\n\n这个表示当前页面每5秒钟刷一下,刷一下~\n\n这个表示当前页面2秒后跳到首页~\n\n页面直接跳转到腾讯网~\n所以,当我们下次遇到“登录成功,正在跳转到您之前访问页面……”的时候,可以使用的这个refresh刷新,跳转功能,可以说是成本最低的。\n您可以狠狠地点击这里:meta与当前页面定时刷新Demo\n\n上面 Demo 效果就是上面第1个示例代码效果。\n根据我的测试,此特性包括IE7在内的浏览器都是支持的。\n问题来了:为何 meta 跳转不火呢?\n大家可以看到,meta 跳转,使用方便,不用写 JS,不用会后台代码,定时跳转刷新什么的玩得照样很溜,而且兼容性好,为啥总感觉不温不火,很少看见有人提及呢?\n新晋的小伙伴不知有没有听过这么一个词,叫做“万恶的IE6年代”。\n据说,当年,这一批老旧的浏览器,问题很多,其中就有对meta 两个小小的不友好。我也是听说,不一定准确。坊间是这么传闻的:\n\n时间设为0的跳转,有时候页面会闪一下;\n跳转到其他页面,浏览器后退按钮是不能用的;\n\n但是啊,现在是什么年代啊,监狱风云都拍到第二季了,这些老问题,我觉得就可以忽略不计了。\n不妨大胆试试 meta 跳转,好好利用下浏览器的原生特性,说不定就会发现比什么 JS 跳转之流用得更开心。\n\n所以,在文章的最后有一个小想法 —— 我们是不是也可以利用这个方法实现无数个链接 301 重定向( URL 转发),再也不需要担心是否需要主机+Nginx 之类!', 'bodyHTML': '

这个方法最开始是在 Linlin Yan (颜林林) 的 GitHub Pages 上第一次看到。后来,随着自己也用上了,就开始有了更深一些的认识。

\n\n

跳转域名

\n

yanlinlin82/yanlinlin82.github.io 看到一个通过 https://yanlinlin82.github.io 可以直接重定向到 https://yanlinlin.cn/ 的用法 —— 只需要把 index.html 写成这样就可以:

\n
<!DOCTYPE html>\n<html>\n  <head><meta http-equiv="refresh" content="0; url=https://yanlinlin.cn/"></head>\n  <body></body>\n</html>
\n

页面定时跳转与刷新

\n

这部分的内容主要来源自:《小tip: 使用meta实现页面的定时刷新或跳转》。

\n
\n

meta 源信息功能之页面定时跳转与刷新

\n

几乎所有的网页头部都有<meta>源信息。除了我们常用的定义编码、关键字(name=”keywords”)、描述(name=”description”)(for SEO),还可以定义视区大小、缩放比例等(for 移动端),如下:

\n
<meta name="viewport" content="width=device-width,initial-scale=1.0">\n
\n

以及,定义网页的过期时间,Cookie 的过期时间等等。

\n

文本要介绍的内容,科科,跟上面都没关系。哦,抱歉,都有关系,只是名称我故意没提到。主角嘛,总要最后闪亮登场!

\n

就是我们网页平时跳转,还可以使用 <meta> 实现,下面几个典型代码示例:

\n
<meta http-equiv="refresh" content="5">
\n

这个表示当前页面每5秒钟刷一下,刷一下~

\n
<meta http-equiv="refresh" content="2; url=\'/\'">
\n

这个表示当前页面2秒后跳到首页~

\n
<meta http-equiv="refresh" content="0; url=\'http://www.qq.com/\'">
\n

页面直接跳转到腾讯网~

\n

所以,当我们下次遇到“登录成功,正在跳转到您之前访问页面……”的时候,可以使用<meta>的这个refresh刷新,跳转功能,可以说是成本最低的。

\n

您可以狠狠地点击这里:meta与当前页面定时刷新Demo
\nmeta-refresh

\n

上面 Demo 效果就是上面第1个示例代码效果。

\n

根据我的测试,此特性包括IE7在内的浏览器都是支持的。

\n

问题来了:为何 meta 跳转不火呢?

\n

大家可以看到,meta 跳转,使用方便,不用写 JS,不用会后台代码,定时跳转刷新什么的玩得照样很溜,而且兼容性好,为啥总感觉不温不火,很少看见有人提及呢?

\n

新晋的小伙伴不知有没有听过这么一个词,叫做“万恶的IE6年代”。

\n

据说,当年,这一批老旧的浏览器,问题很多,其中就有对meta 两个小小的不友好。我也是听说,不一定准确。坊间是这么传闻的:

\n
    \n
  • 时间设为0的跳转,有时候页面会闪一下;
  • \n
  • 跳转到其他页面,浏览器后退按钮是不能用的;
  • \n
\n

但是啊,现在是什么年代啊,监狱风云都拍到第二季了,这些老问题,我觉得就可以忽略不计了。

\n

不妨大胆试试 meta 跳转,好好利用下浏览器的原生特性,说不定就会发现比什么 JS 跳转之流用得更开心。

\n
\n

所以,在文章的最后有一个小想法 —— 我们是不是也可以利用这个方法实现无数个链接 301 重定向( URL 转发),再也不需要担心是否需要主机+Nginx 之类!

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': [{'name': '公众号'}]}, 'comments': {'nodes': []}}, {'title': '2022 年的十大生物学突破', 'number': 32, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/32', 'createdAt': '2023-12-01T03:39:00Z', 'lastEditedAt': None, 'updatedAt': '2024-01-04T05:45:16Z', 'body': '> **作者 |** [Niko McCarty](https://substack.com/profile/11154869-niko-mccarty) \r\n> **翻译 |** [章鱼猫先生](https://www.yuque.com/shenweiyan) \r\n> **日期 |** 原文发表于 2022.12.10 \r\n> **来源 |** [Biology Breakthroughs of 2022](https://cell.substack.com/p/biology-breakthroughs-2022) - Codon \r\n\r\n> 您正在阅读 Codon,这是一份关于生物 + 技术进步和为人类创造更光明未来的想法的时事通讯。 \r\n> 这是今年的最后一部作品。几周后我会在这里见到你! \r\n\r\n\r\n\r\n

\r\n
\r\n 大约 1950 年代,戴着加压氧气面罩的男子\r\n

\r\n\r\n> "当你经历历史时,历史永远不会像历史。它总是看起来很混乱和凌乱,而且总是让人感觉不舒服。" \r\n> —— 约翰·W·加德纳\r\n\r\n许多我非常敬佩的作家都对“进步的停滞”写出了令人信服的论战。科学越来越难,发现越来越小(平均而言),这两件事都很糟糕。\r\n\r\n如果你召集来自世界顶级院系的 93 位物理学家,让他们将 1910 年代获得诺贝尔奖的发现与 80 年代的另一个发现进行比较,他们通常会说更早的发现更重要。\r\n\r\n与五十年前相比,今天实现技术飞跃也更加困难。将计算机芯片上的晶体管数量增加一倍(又名摩尔定律)需要的研究人员数量是 1970 年代初期的 [18 倍](https://www.aeaweb.org/articles?id=10.1257/aer.20180338)。今天发表的学术论文被美国专利引用的可能性不到 30 年前发表的论文的[一半](https://mattsclancy.substack.com/p/science-is-getting-harder)。\r\n\r\n这些不断缩减的回报正处于历史高位之中。\r\n\r\n美国每年授予超过 50,000 个科学和工程博士学位;这个数字在 1960 年还不到 10,000。联邦对科学的资助也(基本上)处于历史最高水平。科学论文的总数呈指数级增长,但每篇论文的平均作者人数在过去一百年里大约翻了两番。\r\n

\r\n
\r\n From "The Science of Science" by Wang and Barabási.\r\n

\r\n\r\n出于某种原因,这些都是生物学进步的不完美指标。但是有很多零散的证据表明,科学正在变得越来越不划算,即使感觉进步从未像现在这样快。我相信——基于轶事证据,真的——如果以每年获得诺贝尔奖的发现为基准,生物技术不会停滞不前。只是诺贝尔奖每年都会颁发一次,而且不乏令人惊叹的论文在排队等待获得最高奖项。所以,当然,并不是每个有价值的人都会赢。\r\n\r\n哦,如果你拿我之前提到的物理学调查结果,对医学和化学做同样的实验,结果就会颠倒过来——20 世纪下半叶发现的相对重要性超过了上半叶。\r\n\r\n不管停滞与否,生物学都存在巨大的低效率。它可以——应该!- 移动得更快。\r\n\r\n许多论文需要一年多的时间才能发表,在期刊官僚的严密监视下,被搁置在数字化的边缘。漫长的等待可能也不值得——同行评审通常是无用的,而且很多糟糕的科学无论如何都能通过。许多伟大的想法也从来没有发表在论文上,因为,好吧,他们从来没有得到资助。NIH 拨款审查非常不一致。如果您向 43 位不同的审稿人提供 25 份拨款建议,他们的评定者间可靠性(衡量分数一致性的指标)基本上为零,即使拨款已经获得资金和先前评审小组的高分!给予相同审稿人的无资金资助与有资金资助的资助得分一样。\r\n\r\n那么生物学文献呢?那也是一团糟。山姆·罗德里克斯 ([Sam Rodriques](https://www.sam-rodriques.com/post/why-is-progress-in-biology-so-slow)) 在最近的一篇文章中写道,科学论文“因委托而变得不可靠”,并且“因遗漏而变得不可靠”。换句话说,一些研究(一小部分)只是编造的。教授或学生为了发表论文而捏造数字,如果有人说他们在胡说八道,编辑可能要过[好几年](https://newscience.substack.com/p/laws-of-science)才会撤稿。\r\n\r\n不过,更大的问题可能是疏忽。科学期刊喜欢发表积极的结果,所以大多数消极的发现永远不会出现在光鲜的期刊上。如果有人进行的实验表明药物 A 与受体 B 结合,他们会发表它——但忽略提及药物 A 不会通过 Z 与受体 C 结合。无效结果很少传给科学家,他们中的许多人已经几个月来一次又一次尝试实验的痛苦经历,后来才发现 1970 年代的一篇不起眼的论文使他们所有的努力都变得毫无意义。\r\n\r\n我告诉你这些悲伤的事情——停滞不前的科学和可怕的低效率的故事——是为了说明一个观点:**生物学在去年取得了如此大的进步,真是令人惊讶**。生物学的进步证明了人类渴望探索、失败,然后继续前进的愿望。这份时事通讯庆祝人类的成就,并重点介绍了过去 12 个月**生物学领域的十大进步**。\r\n\r\n此列表中的所有内容均来自 Codon 的上一期,因此希望您能在评论中指出我的错误和遗漏。我的入选标准很简单:该列表仅包括 2022 年期间发布到 bioRxiv 或发表在期刊上的论文。我不包括公司成就——这实际上可能是它自己的列表——除非他们发布了数据。(入选)列表中的一些项目包括了多篇论文,因为整个子领域发展得非常快。\r\n\r\n汇总“十佳排名”最大的危险是完全主观的,有很多优秀的东西没有入选,而且很多其他作家已经做到了(虽然我还没有看到专门针对生物学的清单)。诺亚·史密斯 (Noah Smith) 发布了他 2023 年的技术乐观主义清单 ([techno-optimism list](https://noahpinion.substack.com/p/techno-optimism-for-2023)),其中包括对生物技术的简要提及,而《大西洋月刊》(The Atlantic) 发表了他们的 "年度突破 ([breakthroughs of the year](https://www.theatlantic.com/newsletters/archive/2022/12/technology-medicine-law-ai-10-breakthroughs-2022/672390/))",然后立即将该文章设置为付费文章。\r\n\r\n然而,有必要专门为生物学列出一份完整的榜单,因为很多伟大的事情在人工智能的阴影下被忽略了。人类基因组计划(始于 1990 年)终于在[今年完成了](https://www.science.org/toc/science/376/6588),一个庞大的科学家团队填补了最后 8% 的序列空白。科学家们还使用 mirror-image DNA 聚合酶制作了镜像 DNA ([mirror-image DNA](https://www.nature.com/articles/s41587-022-01337-8)),并发现了一类新的 CRISPR 蛋白质,它们可以[剪切蛋白质](https://cell.substack.com/p/crispr-can-cut-proteins-too-index)而不是基因。机器学习正在蛋白质工程中掀起波澜,例如有一种基于算法被设计出来的酶,这种酶可以比自然界中发现的任何酶更快地[分解 PET 塑料](https://cell.substack.com/p/ai-designed-enzyme-eats-plastic)。\r\n\r\n我不确定今年的进展是否与生物进展是否整体停滞不前有关。但有一件事是不变的:生物学变得越来越奇怪,而我会一直关注它。\r\n\r\n### 10. 走向合成细胞\r\n\r\n从纯化学成分构建合成细胞是生物学的圣杯。如果实现了这一壮举,将证明我们已足够详细地理解生命运作的大体轮廓,并有足够的细节可以在实验室中重现它。这也将成为定制细胞的起点,这些细胞可以检测有毒污染或制造药物,同时又不会成为生物安全风险或存在感染风险。\r\n\r\n今年有几篇论文推动了合成细胞的发展,但其中有两篇让人印象深刻。第一篇是在 bioRxiv 上发表的预印本,据称是**首次证明核糖体**(大分子蛋白质,负责合成其他蛋白质)**可以在活细胞之外制造**。这是在合成细胞内从头生产蛋白质的重要起点。\r\n\r\n我们还在合成细胞分裂方面取得了重要进展。一项研究报告说,仅使用五种蛋白质就可以在脂肪泡中制造合成分裂环!当这些蛋白质聚集在一起时,它们会收缩并向气泡施加力(下面的 GIF)。 \r\n

\r\n
\r\n 合成分裂环在气泡内形成的延时摄影\r\n

\r\n\r\n### 9. 更好的碱基编辑器\r\n\r\n早在 2016 年,《自然》杂志的一篇论文就报道了第一个碱基编辑蛋白,它可以将 DNA 中的 "C" 替换为 "T",而无需将基因组一分为二。它的重要性立即显而易见——许多严重的遗传疾病是由 DNA 中的单个碱基交换引起的,现在这些突变可以被修复。\r\n\r\n碱基编辑器已经成熟。这些基因编辑蛋白在发明后仅仅五年就以创纪录的速度进入临床试验,目前 Verve、Beam 和其他公司正在进行针对镰状细胞病、高胆固醇和 Stargardt 病的[试验](https://www.nature.com/articles/d41573-022-00124-z)。\r\n\r\n然而,碱基编辑的主要挑战之一是编辑线粒体基因组很棘手,[许多遗传疾病](https://www.chop.edu/conditions-diseases/mitochondrial-dna-common-mutation-syndromes)都源于此。早在 2020 年,[一篇论文](https://www.nature.com/articles/s41586-020-2477-4)就表明碱基编辑器可以成功进入线粒体并使 "C" 变为 "T",但其前景并不乐观。今年 5 月,[一篇后续论文](https://www.nature.com/articles/s41586-022-04836-5)称,实际上,这些线粒体基因编辑器诱发了 "大量" 脱靶突变,这意味着它们编辑的位置比预期的要多,弊大于利。\r\n\r\n但创新不会因失败而受阻。仅今年一年就至少发表了**三篇论文**,使线粒体碱基编辑器变得[更小](https://www.nature.com/articles/s41467-022-34784-7)或[更准确](https://doi.org/10.1016/j.cell.2022.03.039)。让碱基编辑酶进入线粒体或编辑其 DNA 从未如此简单。我相信我们很快就会看到一些针对线粒体相关疾病的临床试验。\r\n\r\n### 8. 噬菌体传播病毒\r\n\r\n今年对噬菌体来说是个好年头。这真的很合适,因为它也是 Felix d\'Herelle 著名实验 **100 周年纪念日**。1922 年,这位巴黎微生物学家证明噬菌体(感染细菌的小病毒)[可以根除](https://jamanetwork.com/journals/jamapediatrics/article-abstract/1173780)兔子和小动物体内的 "痢疾杆菌和其他杆菌"。\r\n\r\n我们现在正经历着临床疗法的准复兴时期,噬菌体经常被用来消除抗生素无效的感染(尤其是在欧洲医院)。几周前,一个欧洲科学家团队使用实验性噬菌体疗法[挽救了一名幼儿的生命](https://www.nature.com/articles/s41467-022-33294-w)。器官移植后,这个小男孩感染了抗生素无法清除的耐药性感染。在用定制的噬菌体鸡尾酒 (a custom-made phage cocktail) 治疗两年多后,孩子在家中恢复了健康。\r\n\r\n5 月,丹佛的一个团队使用噬菌体治疗一名患有严重囊性纤维化的男孩的脓肿分枝杆菌感染。噬菌体将感染控制了一年多,直到获得供体肺。我相信我们会在 2023 年看到定制噬菌体疗法进入临床。 \r\n

\r\n
\r\n

\r\n\r\n\r\n### 7. 血友病基因疗法\r\n\r\n[Hemgenix](https://www.fda.gov/vaccines-blood-biologics/vaccines/hemgenix) 是一种治疗 B 型血友病的基因疗法,几个月前获得了 FDA 的批准。它的价格达到了 350 万美元,使其成为有史以来最昂贵的药物(这并不好)。根据 III 期临床试验数据,它在患者的是安全有效期[至少两年](https://hemophilianewstoday.com/news/hemgenix-gene-therapy-benefits-sustained-2-years-phase-3-hope-b/)。\r\n\r\n血友病 A 的基因治疗进展缓慢,该病由一种名为 VIII 的不同凝血蛋白突变引起。5 月的一项研究表明,针对肝脏的基因疗法在非人类灵长类动物中效果很好,可以导致 "总凝血因子 VIII 输出增加 10 倍以上"。3 月份发表的一项有 134 名参与者参与的 I/II 期临床试验表明,使用腺相关病毒进行的基因疗法,也用于肝脏,可减少血友病患者的出血事件。但是,它带来了很多副作用;每个试验参与者至少有一次不良事件。尽管如此,血友病仍是基因治疗的 "低悬" 目标之一,这些试验是其他正在进行中的目标的有用酸性测试。\r\n\r\n### 6. 合成胚胎\r\n\r\n今年,从老鼠身上采集的干细胞被用来制造 "类胚胎结构",其中包含工作的肠道、跳动的心脏和头脑的雏形,而不需要精子或卵子。\r\n\r\n以色列的 Jacob Hanna 团队发表了一篇最初的论文,于 8 月[在 Cell 上发表](https://doi.org/10.1016/j.cell.2022.07.028)。据《卫报》报道,这些作者后来成立了一家名为 Renewal Bio 的[公司](https://www.theguardian.com/science/2022/aug/03/scientists-create-worlds-first-synthetic-embryos),"旨在培养人类合成胚胎,为医疗条件提供组织和细胞"。剑桥大学和加州理工学院的一个团队也在 8 月 2 日发布了一份[预印本](https://doi.org/10.1101/2022.08.01.502371),表明这些 "合成胚胎"准确地概括了 "从胚胎第 5.5 天到第 8.5 天的发育事件,包括原肠胚形成、前后轴的形成、大脑,跳动的心脏结构,以及胚胎外组织(包括卵黄囊和绒毛膜)的发育。"\r\n\r\n合成胚胎——正确形成的概率只有 0.5% 左右——有几个潜在的用途。例如,这些结构可以用于研究器官在发育过程中的形成,也可用于在不使用真实胚胎的情况下测试药物。 \r\n

\r\n
\r\n Embryoids after six days. From Kasey Lau et al. on bioRxiv. Link\r\n

\r\n\r\n### 5. 细胞重编程\r\n\r\n今年的一大亮点:首次证明仅靠化学物质就能将人体细胞[重新编程为干细胞](https://www.nature.com/articles/s41586-022-04593-5)。这一突破需要十多年的时间,并需使用 11 种不同的化学物质,以及一到两个月的工作时间,所以仍需要一些微调。早在 2013 年,同一个小组就已使用这种方法实现了[小鼠细胞](https://www.science.org/doi/10.1126/science.1239278)的转化,但人类细胞的转化过程要困难得多。\r\n\r\n这也不是第一项重新编程人类细胞的研究。这一荣誉属于山中伸弥 (Shinya Yamanaka),他在 2006 年通过表达四种蛋白质(现在著名的 "Yamanaka 因子")对 iPS 细胞进行了重编程。在随后的几十年中,其他研究小组使用病毒或 mRNA 对细胞进行重编程。但这种仅使用化学物质的方法脱颖而出,因为它在体外使用简单,而且化学混合物可以通过静脉注射输送到体内——不需要基因编辑。该方法提供了一种相对简单的工具来生成可用于再生医学的人类多能干细胞。\r\n\r\n### 4. 植物更容易设计\r\n\r\n我们生活在人类世,这是人类历史上一个可怕的时刻,**人造材料的重量超过地球上所有的生物量**,而且重量每年都在继续增加一倍。 \r\n

\r\n
\r\n "Global human-made mass exceeds all living biomass," by Elhacham E et al. in Nature. Link\r\n

\r\n\r\n在我们现有的生物质中,据估计有 83% 由植物持有。如果我们想要走出这场行星垃圾场的困境,那么,那么我们可能不得不对植物进行工程改造:让它们捕获更多的碳,[增强它们的光合作用](https://cell.substack.com/p/hacking-photosynthesis),种植生产更多的食物,等等!\r\n\r\n幸运的是,做到这一点从未如此简单。几十年来,合成生物学家已经对细菌和哺乳动物细胞进行了改造,使其具有越来越复杂的遗传回路,即使植物在很大程度上被忽视了。今年,两项重要进展改变了平衡。\r\n\r\n先是基因编辑技术,如 CRISPR,现在已经过优化,可以在植物中更好地发挥作用。例如,Prime 编辑器是可以插入、删除或交换 DNA 的 "搜索和替换" 基因编辑器。与其他 Prime 编辑器相比,新的 Plant Prime Editor 在植物细胞中的效率提高了 [3.4 倍](https://www.nature.com/articles/s41587-022-01254-w),并被用于在实验室中迅速使水稻植物对除草剂产生耐受性。\r\n\r\n但更大的进步是:斯坦福大学的一个团队发布了[一个完整的基因工具包](https://www.science.org/doi/10.1126/science.abo4326),可以像我们对细菌进行编程一样对植物进行 "编程"。新工具包包括大量合成启动子和转录因子,可用于控制植物中的基因表达。这些遗传部分被用于构建能够在本塞姆氏烟草和拟南芥中进行布尔逻辑运算的基因回路。作者还建立了逻辑门,可以控制植物根部的基因表达水平,从而控制它们的侧向密度。\r\n\r\n

\r\n
\r\n A genetic circuit controls how many lateral roots shoot out from a plant’s roots. Lateral density increases from left to right, with a wildtype plant shown on the far right. From Brophy et al. on bioRxiv.\r\n

\r\n\r\n### 3. 走向负碳\r\n\r\n生物学的一个众所周知的困难部分是难以扩展(进行大规模的研究)。在试管中改造一个能将糖转化为抗癌药物的细胞是一回事,但在一个千升生物反应器中做同样的事却是完全不同的挑战。\r\n\r\n这就是像 [LanzaTech](https://lanzatech.com/) 这样的公司令人兴奋的原因。他们实际上已经在工业工厂扩大了生物学规模。他们有试点设施,将工厂的废碳回收成燃料和化学品。这些工厂每年可以生产数千亿加仑的燃料,并且已经达到相当于每年减少数千辆汽车上路的排放量。\r\n\r\n几个月前,来自 LanzaTech 和西北大学的科学家们达到了[另一个里程碑](https://www.nature.com/articles/s41587-021-01195-w):使用一种名为 Clostridium autoethanogenum 的工程自养生物,他们在具有负碳足迹的过程中以工业规模生产丙酮和异丙醇。 "与导致温室气体释放的传统生产过程不同,我们的过程可以固定碳," 他们在发表的论文中写道。这是大规模生物学向前迈出的一大步。经过改造的微生物可以在不拖累大气的情况下改善污染物并产生化学物质。\r\n\r\n### 2. 异种移植成为现实\r\n\r\n这将作为 "异种移植年" 载入人类史册。异种移植的历史可以追溯到 20 世纪 60 年代中期——法国外科医生勒内·库斯 (Renè Kuss) 将猪肾移植到人体中,结果很快被患者的身体排斥——异种移植一直是一个失败的领域。最著名的例子可能是 80 年代 Stephanie Beauclair 或 Baby Fae 的手术,她从狒狒那里接受了一颗心脏,但不久后就去世了。\r\n\r\n不过,在过去四十年里,我们在从猪身上提取心脏并将其植入人体方面做得更好,因为基因编辑技术正在改进。现在比以往任何时候都更容易在猪的细胞中找到所有导致我们的身体排斥该器官的有害蛋白质,并从基因组中[系统地消除](https://www.science.org/doi/10.1126/science.aad1191)这些蛋白质编码基因。但进步从来都不是没有陷阱的。\r\n\r\n今年 1 月 7 日,马里兰大学的一组外科医生将[一颗猪的心脏移植](https://www.technologyreview.com/2022/01/11/1043374/gene-edited-pigs-heart-transplant/)到 57 岁的老大卫贝内特体内,[两个月后](https://www.technologyreview.com/2022/05/04/1051725/xenotransplant-patient-died-received-heart-infected-with-pig-virus/)他去世了。\r\n\r\n5 月,两只猪的肾脏被移植到脑死亡患者体内,并进行了 54 小时的监测,这让沮丧过后变得乐观起来。两个肾脏都产生了尿液,活组织检查没有显示出任何器官排斥的迹象。\r\n\r\n心脏移植可能因为器官感染了猪病毒而失败,但肾移植研究的作者没有检测到这种病毒。猪肾可能很快就会进入人们的生活。\r\n\r\n### 1. 我们离终结疟疾从未如此近\r\n\r\n如果您相信约翰·惠特菲尔德 (John Whitfield) 2002 年在《[自然](https://www.nature.com/articles/news021001-6)》杂志发表的这篇文章(该说法未被引用),"疟疾已经杀死了所有曾经生活过的人的一半"。即使该说法是错误的,在整个人类历史上,蚊子也已经集体杀死了数十亿人。昆虫混蛋干掉了亚历山大大帝、哥特人阿拉里克和但丁。而且,在 2021 年,疟疾仍导致约 620,000 人死亡。这是令人震惊、悲伤和可以预防的。但今年是取得惊人进步的一年。\r\n\r\n一种称为 R21/Matrix-M 的疟疾疫苗在四个非洲国家进行了 III 期试验。它在幼儿中的总体疗效为 [75%](https://www.medpagetoday.com/meetingcoverage/astmh/101561)。这是个好消息。在马里进行的一项 II 期试验还测试了一种名为 CIS43LS 的抗体,用于对抗健康成人中的恶性疟原虫感染。在六个月的时间里,单次注射的疗效为 [88.2%](https://www.nejm.org/doi/full/10.1056/NEJMoa2206966)。\r\n\r\n不过,唯一能有效预防疟疾 90% 以上的免疫原是子孢子,这是一种在蚊子生命周期中形成的类孢子部分。这些子孢子被注射到手臂中并[用作疫苗](https://www.science.org/doi/10.1126/scitranslmed.abj3776),但显然很难从真正的蚊子身上收集到这些东西。\r\n\r\n本月早些时候,研究人员在实验室中创造了 "[数亿](https://www.nature.com/articles/s41586-022-05466-7)" 子孢子,而不需要蚊子。他们基本上重新创建了整个"疟原虫从传染性配子体到传染性配子体的全部生命周期,而不需要蚊子。" 这项新技术将有助于更快、更便宜地研制出抗疟疾疫苗。\r\n\r\n

\r\n
\r\n

', 'bodyText': '作者 | Niko McCarty\n翻译 | 章鱼猫先生\n日期 | 原文发表于 2022.12.10\n来源 | Biology Breakthroughs of 2022 - Codon\n\n\n您正在阅读 Codon,这是一份关于生物 + 技术进步和为人类创造更光明未来的想法的时事通讯。\n这是今年的最后一部作品。几周后我会在这里见到你!\n\n\n\n \n 大约 1950 年代,戴着加压氧气面罩的男子\n\n\n"当你经历历史时,历史永远不会像历史。它总是看起来很混乱和凌乱,而且总是让人感觉不舒服。"\n—— 约翰·W·加德纳\n\n许多我非常敬佩的作家都对“进步的停滞”写出了令人信服的论战。科学越来越难,发现越来越小(平均而言),这两件事都很糟糕。\n如果你召集来自世界顶级院系的 93 位物理学家,让他们将 1910 年代获得诺贝尔奖的发现与 80 年代的另一个发现进行比较,他们通常会说更早的发现更重要。\n与五十年前相比,今天实现技术飞跃也更加困难。将计算机芯片上的晶体管数量增加一倍(又名摩尔定律)需要的研究人员数量是 1970 年代初期的 18 倍。今天发表的学术论文被美国专利引用的可能性不到 30 年前发表的论文的一半。\n这些不断缩减的回报正处于历史高位之中。\n美国每年授予超过 50,000 个科学和工程博士学位;这个数字在 1960 年还不到 10,000。联邦对科学的资助也(基本上)处于历史最高水平。科学论文的总数呈指数级增长,但每篇论文的平均作者人数在过去一百年里大约翻了两番。\n\n \n From "The Science of Science" by Wang and Barabási.\n\n出于某种原因,这些都是生物学进步的不完美指标。但是有很多零散的证据表明,科学正在变得越来越不划算,即使感觉进步从未像现在这样快。我相信——基于轶事证据,真的——如果以每年获得诺贝尔奖的发现为基准,生物技术不会停滞不前。只是诺贝尔奖每年都会颁发一次,而且不乏令人惊叹的论文在排队等待获得最高奖项。所以,当然,并不是每个有价值的人都会赢。\n哦,如果你拿我之前提到的物理学调查结果,对医学和化学做同样的实验,结果就会颠倒过来——20 世纪下半叶发现的相对重要性超过了上半叶。\n不管停滞与否,生物学都存在巨大的低效率。它可以——应该!- 移动得更快。\n许多论文需要一年多的时间才能发表,在期刊官僚的严密监视下,被搁置在数字化的边缘。漫长的等待可能也不值得——同行评审通常是无用的,而且很多糟糕的科学无论如何都能通过。许多伟大的想法也从来没有发表在论文上,因为,好吧,他们从来没有得到资助。NIH 拨款审查非常不一致。如果您向 43 位不同的审稿人提供 25 份拨款建议,他们的评定者间可靠性(衡量分数一致性的指标)基本上为零,即使拨款已经获得资金和先前评审小组的高分!给予相同审稿人的无资金资助与有资金资助的资助得分一样。\n那么生物学文献呢?那也是一团糟。山姆·罗德里克斯 (Sam Rodriques) 在最近的一篇文章中写道,科学论文“因委托而变得不可靠”,并且“因遗漏而变得不可靠”。换句话说,一些研究(一小部分)只是编造的。教授或学生为了发表论文而捏造数字,如果有人说他们在胡说八道,编辑可能要过好几年才会撤稿。\n不过,更大的问题可能是疏忽。科学期刊喜欢发表积极的结果,所以大多数消极的发现永远不会出现在光鲜的期刊上。如果有人进行的实验表明药物 A 与受体 B 结合,他们会发表它——但忽略提及药物 A 不会通过 Z 与受体 C 结合。无效结果很少传给科学家,他们中的许多人已经几个月来一次又一次尝试实验的痛苦经历,后来才发现 1970 年代的一篇不起眼的论文使他们所有的努力都变得毫无意义。\n我告诉你这些悲伤的事情——停滞不前的科学和可怕的低效率的故事——是为了说明一个观点:生物学在去年取得了如此大的进步,真是令人惊讶。生物学的进步证明了人类渴望探索、失败,然后继续前进的愿望。这份时事通讯庆祝人类的成就,并重点介绍了过去 12 个月生物学领域的十大进步。\n此列表中的所有内容均来自 Codon 的上一期,因此希望您能在评论中指出我的错误和遗漏。我的入选标准很简单:该列表仅包括 2022 年期间发布到 bioRxiv 或发表在期刊上的论文。我不包括公司成就——这实际上可能是它自己的列表——除非他们发布了数据。(入选)列表中的一些项目包括了多篇论文,因为整个子领域发展得非常快。\n汇总“十佳排名”最大的危险是完全主观的,有很多优秀的东西没有入选,而且很多其他作家已经做到了(虽然我还没有看到专门针对生物学的清单)。诺亚·史密斯 (Noah Smith) 发布了他 2023 年的技术乐观主义清单 (techno-optimism list),其中包括对生物技术的简要提及,而《大西洋月刊》(The Atlantic) 发表了他们的 "年度突破 (breakthroughs of the year)",然后立即将该文章设置为付费文章。\n然而,有必要专门为生物学列出一份完整的榜单,因为很多伟大的事情在人工智能的阴影下被忽略了。人类基因组计划(始于 1990 年)终于在今年完成了,一个庞大的科学家团队填补了最后 8% 的序列空白。科学家们还使用 mirror-image DNA 聚合酶制作了镜像 DNA (mirror-image DNA),并发现了一类新的 CRISPR 蛋白质,它们可以剪切蛋白质而不是基因。机器学习正在蛋白质工程中掀起波澜,例如有一种基于算法被设计出来的酶,这种酶可以比自然界中发现的任何酶更快地分解 PET 塑料。\n我不确定今年的进展是否与生物进展是否整体停滞不前有关。但有一件事是不变的:生物学变得越来越奇怪,而我会一直关注它。\n10. 走向合成细胞\n从纯化学成分构建合成细胞是生物学的圣杯。如果实现了这一壮举,将证明我们已足够详细地理解生命运作的大体轮廓,并有足够的细节可以在实验室中重现它。这也将成为定制细胞的起点,这些细胞可以检测有毒污染或制造药物,同时又不会成为生物安全风险或存在感染风险。\n今年有几篇论文推动了合成细胞的发展,但其中有两篇让人印象深刻。第一篇是在 bioRxiv 上发表的预印本,据称是首次证明核糖体(大分子蛋白质,负责合成其他蛋白质)可以在活细胞之外制造。这是在合成细胞内从头生产蛋白质的重要起点。\n我们还在合成细胞分裂方面取得了重要进展。一项研究报告说,仅使用五种蛋白质就可以在脂肪泡中制造合成分裂环!当这些蛋白质聚集在一起时,它们会收缩并向气泡施加力(下面的 GIF)。\n\n \n 合成分裂环在气泡内形成的延时摄影\n\n9. 更好的碱基编辑器\n早在 2016 年,《自然》杂志的一篇论文就报道了第一个碱基编辑蛋白,它可以将 DNA 中的 "C" 替换为 "T",而无需将基因组一分为二。它的重要性立即显而易见——许多严重的遗传疾病是由 DNA 中的单个碱基交换引起的,现在这些突变可以被修复。\n碱基编辑器已经成熟。这些基因编辑蛋白在发明后仅仅五年就以创纪录的速度进入临床试验,目前 Verve、Beam 和其他公司正在进行针对镰状细胞病、高胆固醇和 Stargardt 病的试验。\n然而,碱基编辑的主要挑战之一是编辑线粒体基因组很棘手,许多遗传疾病都源于此。早在 2020 年,一篇论文就表明碱基编辑器可以成功进入线粒体并使 "C" 变为 "T",但其前景并不乐观。今年 5 月,一篇后续论文称,实际上,这些线粒体基因编辑器诱发了 "大量" 脱靶突变,这意味着它们编辑的位置比预期的要多,弊大于利。\n但创新不会因失败而受阻。仅今年一年就至少发表了三篇论文,使线粒体碱基编辑器变得更小或更准确。让碱基编辑酶进入线粒体或编辑其 DNA 从未如此简单。我相信我们很快就会看到一些针对线粒体相关疾病的临床试验。\n8. 噬菌体传播病毒\n今年对噬菌体来说是个好年头。这真的很合适,因为它也是 Felix d\'Herelle 著名实验 100 周年纪念日。1922 年,这位巴黎微生物学家证明噬菌体(感染细菌的小病毒)可以根除兔子和小动物体内的 "痢疾杆菌和其他杆菌"。\n我们现在正经历着临床疗法的准复兴时期,噬菌体经常被用来消除抗生素无效的感染(尤其是在欧洲医院)。几周前,一个欧洲科学家团队使用实验性噬菌体疗法挽救了一名幼儿的生命。器官移植后,这个小男孩感染了抗生素无法清除的耐药性感染。在用定制的噬菌体鸡尾酒 (a custom-made phage cocktail) 治疗两年多后,孩子在家中恢复了健康。\n5 月,丹佛的一个团队使用噬菌体治疗一名患有严重囊性纤维化的男孩的脓肿分枝杆菌感染。噬菌体将感染控制了一年多,直到获得供体肺。我相信我们会在 2023 年看到定制噬菌体疗法进入临床。\n\n \n\n7. 血友病基因疗法\nHemgenix 是一种治疗 B 型血友病的基因疗法,几个月前获得了 FDA 的批准。它的价格达到了 350 万美元,使其成为有史以来最昂贵的药物(这并不好)。根据 III 期临床试验数据,它在患者的是安全有效期至少两年。\n血友病 A 的基因治疗进展缓慢,该病由一种名为 VIII 的不同凝血蛋白突变引起。5 月的一项研究表明,针对肝脏的基因疗法在非人类灵长类动物中效果很好,可以导致 "总凝血因子 VIII 输出增加 10 倍以上"。3 月份发表的一项有 134 名参与者参与的 I/II 期临床试验表明,使用腺相关病毒进行的基因疗法,也用于肝脏,可减少血友病患者的出血事件。但是,它带来了很多副作用;每个试验参与者至少有一次不良事件。尽管如此,血友病仍是基因治疗的 "低悬" 目标之一,这些试验是其他正在进行中的目标的有用酸性测试。\n6. 合成胚胎\n今年,从老鼠身上采集的干细胞被用来制造 "类胚胎结构",其中包含工作的肠道、跳动的心脏和头脑的雏形,而不需要精子或卵子。\n以色列的 Jacob Hanna 团队发表了一篇最初的论文,于 8 月在 Cell 上发表。据《卫报》报道,这些作者后来成立了一家名为 Renewal Bio 的公司,"旨在培养人类合成胚胎,为医疗条件提供组织和细胞"。剑桥大学和加州理工学院的一个团队也在 8 月 2 日发布了一份预印本,表明这些 "合成胚胎"准确地概括了 "从胚胎第 5.5 天到第 8.5 天的发育事件,包括原肠胚形成、前后轴的形成、大脑,跳动的心脏结构,以及胚胎外组织(包括卵黄囊和绒毛膜)的发育。"\n合成胚胎——正确形成的概率只有 0.5% 左右——有几个潜在的用途。例如,这些结构可以用于研究器官在发育过程中的形成,也可用于在不使用真实胚胎的情况下测试药物。\n\n \n Embryoids after six days. From Kasey Lau et al. on bioRxiv. Link\n\n5. 细胞重编程\n今年的一大亮点:首次证明仅靠化学物质就能将人体细胞重新编程为干细胞。这一突破需要十多年的时间,并需使用 11 种不同的化学物质,以及一到两个月的工作时间,所以仍需要一些微调。早在 2013 年,同一个小组就已使用这种方法实现了小鼠细胞的转化,但人类细胞的转化过程要困难得多。\n这也不是第一项重新编程人类细胞的研究。这一荣誉属于山中伸弥 (Shinya Yamanaka),他在 2006 年通过表达四种蛋白质(现在著名的 "Yamanaka 因子")对 iPS 细胞进行了重编程。在随后的几十年中,其他研究小组使用病毒或 mRNA 对细胞进行重编程。但这种仅使用化学物质的方法脱颖而出,因为它在体外使用简单,而且化学混合物可以通过静脉注射输送到体内——不需要基因编辑。该方法提供了一种相对简单的工具来生成可用于再生医学的人类多能干细胞。\n4. 植物更容易设计\n我们生活在人类世,这是人类历史上一个可怕的时刻,人造材料的重量超过地球上所有的生物量,而且重量每年都在继续增加一倍。\n\n \n "Global human-made mass exceeds all living biomass," by Elhacham E et al. in Nature. Link\n\n在我们现有的生物质中,据估计有 83% 由植物持有。如果我们想要走出这场行星垃圾场的困境,那么,那么我们可能不得不对植物进行工程改造:让它们捕获更多的碳,增强它们的光合作用,种植生产更多的食物,等等!\n幸运的是,做到这一点从未如此简单。几十年来,合成生物学家已经对细菌和哺乳动物细胞进行了改造,使其具有越来越复杂的遗传回路,即使植物在很大程度上被忽视了。今年,两项重要进展改变了平衡。\n先是基因编辑技术,如 CRISPR,现在已经过优化,可以在植物中更好地发挥作用。例如,Prime 编辑器是可以插入、删除或交换 DNA 的 "搜索和替换" 基因编辑器。与其他 Prime 编辑器相比,新的 Plant Prime Editor 在植物细胞中的效率提高了 3.4 倍,并被用于在实验室中迅速使水稻植物对除草剂产生耐受性。\n但更大的进步是:斯坦福大学的一个团队发布了一个完整的基因工具包,可以像我们对细菌进行编程一样对植物进行 "编程"。新工具包包括大量合成启动子和转录因子,可用于控制植物中的基因表达。这些遗传部分被用于构建能够在本塞姆氏烟草和拟南芥中进行布尔逻辑运算的基因回路。作者还建立了逻辑门,可以控制植物根部的基因表达水平,从而控制它们的侧向密度。\n\n \n A genetic circuit controls how many lateral roots shoot out from a plant’s roots. Lateral density increases from left to right, with a wildtype plant shown on the far right. From Brophy et al. on bioRxiv.\n\n3. 走向负碳\n生物学的一个众所周知的困难部分是难以扩展(进行大规模的研究)。在试管中改造一个能将糖转化为抗癌药物的细胞是一回事,但在一个千升生物反应器中做同样的事却是完全不同的挑战。\n这就是像 LanzaTech 这样的公司令人兴奋的原因。他们实际上已经在工业工厂扩大了生物学规模。他们有试点设施,将工厂的废碳回收成燃料和化学品。这些工厂每年可以生产数千亿加仑的燃料,并且已经达到相当于每年减少数千辆汽车上路的排放量。\n几个月前,来自 LanzaTech 和西北大学的科学家们达到了另一个里程碑:使用一种名为 Clostridium autoethanogenum 的工程自养生物,他们在具有负碳足迹的过程中以工业规模生产丙酮和异丙醇。 "与导致温室气体释放的传统生产过程不同,我们的过程可以固定碳," 他们在发表的论文中写道。这是大规模生物学向前迈出的一大步。经过改造的微生物可以在不拖累大气的情况下改善污染物并产生化学物质。\n2. 异种移植成为现实\n这将作为 "异种移植年" 载入人类史册。异种移植的历史可以追溯到 20 世纪 60 年代中期——法国外科医生勒内·库斯 (Renè Kuss) 将猪肾移植到人体中,结果很快被患者的身体排斥——异种移植一直是一个失败的领域。最著名的例子可能是 80 年代 Stephanie Beauclair 或 Baby Fae 的手术,她从狒狒那里接受了一颗心脏,但不久后就去世了。\n不过,在过去四十年里,我们在从猪身上提取心脏并将其植入人体方面做得更好,因为基因编辑技术正在改进。现在比以往任何时候都更容易在猪的细胞中找到所有导致我们的身体排斥该器官的有害蛋白质,并从基因组中系统地消除这些蛋白质编码基因。但进步从来都不是没有陷阱的。\n今年 1 月 7 日,马里兰大学的一组外科医生将一颗猪的心脏移植到 57 岁的老大卫贝内特体内,两个月后他去世了。\n5 月,两只猪的肾脏被移植到脑死亡患者体内,并进行了 54 小时的监测,这让沮丧过后变得乐观起来。两个肾脏都产生了尿液,活组织检查没有显示出任何器官排斥的迹象。\n心脏移植可能因为器官感染了猪病毒而失败,但肾移植研究的作者没有检测到这种病毒。猪肾可能很快就会进入人们的生活。\n1. 我们离终结疟疾从未如此近\n如果您相信约翰·惠特菲尔德 (John Whitfield) 2002 年在《自然》杂志发表的这篇文章(该说法未被引用),"疟疾已经杀死了所有曾经生活过的人的一半"。即使该说法是错误的,在整个人类历史上,蚊子也已经集体杀死了数十亿人。昆虫混蛋干掉了亚历山大大帝、哥特人阿拉里克和但丁。而且,在 2021 年,疟疾仍导致约 620,000 人死亡。这是令人震惊、悲伤和可以预防的。但今年是取得惊人进步的一年。\n一种称为 R21/Matrix-M 的疟疾疫苗在四个非洲国家进行了 III 期试验。它在幼儿中的总体疗效为 75%。这是个好消息。在马里进行的一项 II 期试验还测试了一种名为 CIS43LS 的抗体,用于对抗健康成人中的恶性疟原虫感染。在六个月的时间里,单次注射的疗效为 88.2%。\n不过,唯一能有效预防疟疾 90% 以上的免疫原是子孢子,这是一种在蚊子生命周期中形成的类孢子部分。这些子孢子被注射到手臂中并用作疫苗,但显然很难从真正的蚊子身上收集到这些东西。\n本月早些时候,研究人员在实验室中创造了 "数亿" 子孢子,而不需要蚊子。他们基本上重新创建了整个"疟原虫从传染性配子体到传染性配子体的全部生命周期,而不需要蚊子。" 这项新技术将有助于更快、更便宜地研制出抗疟疾疫苗。', 'bodyHTML': '
\n

作者 | Niko McCarty
\n翻译 | 章鱼猫先生
\n日期 | 原文发表于 2022.12.10
\n来源 | Biology Breakthroughs of 2022 - Codon

\n
\n
\n

您正在阅读 Codon,这是一份关于生物 + 技术进步和为人类创造更光明未来的想法的时事通讯。
\n这是今年的最后一部作品。几周后我会在这里见到你!

\n
\n\n

\n
\n 大约 1950 年代,戴着加压氧气面罩的男子\n

\n
\n

"当你经历历史时,历史永远不会像历史。它总是看起来很混乱和凌乱,而且总是让人感觉不舒服。"
\n—— 约翰·W·加德纳

\n
\n

许多我非常敬佩的作家都对“进步的停滞”写出了令人信服的论战。科学越来越难,发现越来越小(平均而言),这两件事都很糟糕。

\n

如果你召集来自世界顶级院系的 93 位物理学家,让他们将 1910 年代获得诺贝尔奖的发现与 80 年代的另一个发现进行比较,他们通常会说更早的发现更重要。

\n

与五十年前相比,今天实现技术飞跃也更加困难。将计算机芯片上的晶体管数量增加一倍(又名摩尔定律)需要的研究人员数量是 1970 年代初期的 18 倍。今天发表的学术论文被美国专利引用的可能性不到 30 年前发表的论文的一半

\n

这些不断缩减的回报正处于历史高位之中。

\n

美国每年授予超过 50,000 个科学和工程博士学位;这个数字在 1960 年还不到 10,000。联邦对科学的资助也(基本上)处于历史最高水平。科学论文的总数呈指数级增长,但每篇论文的平均作者人数在过去一百年里大约翻了两番。

\n

\n
\n From "The Science of Science" by Wang and Barabási.\n

\n

出于某种原因,这些都是生物学进步的不完美指标。但是有很多零散的证据表明,科学正在变得越来越不划算,即使感觉进步从未像现在这样快。我相信——基于轶事证据,真的——如果以每年获得诺贝尔奖的发现为基准,生物技术不会停滞不前。只是诺贝尔奖每年都会颁发一次,而且不乏令人惊叹的论文在排队等待获得最高奖项。所以,当然,并不是每个有价值的人都会赢。

\n

哦,如果你拿我之前提到的物理学调查结果,对医学和化学做同样的实验,结果就会颠倒过来——20 世纪下半叶发现的相对重要性超过了上半叶。

\n

不管停滞与否,生物学都存在巨大的低效率。它可以——应该!- 移动得更快。

\n

许多论文需要一年多的时间才能发表,在期刊官僚的严密监视下,被搁置在数字化的边缘。漫长的等待可能也不值得——同行评审通常是无用的,而且很多糟糕的科学无论如何都能通过。许多伟大的想法也从来没有发表在论文上,因为,好吧,他们从来没有得到资助。NIH 拨款审查非常不一致。如果您向 43 位不同的审稿人提供 25 份拨款建议,他们的评定者间可靠性(衡量分数一致性的指标)基本上为零,即使拨款已经获得资金和先前评审小组的高分!给予相同审稿人的无资金资助与有资金资助的资助得分一样。

\n

那么生物学文献呢?那也是一团糟。山姆·罗德里克斯 (Sam Rodriques) 在最近的一篇文章中写道,科学论文“因委托而变得不可靠”,并且“因遗漏而变得不可靠”。换句话说,一些研究(一小部分)只是编造的。教授或学生为了发表论文而捏造数字,如果有人说他们在胡说八道,编辑可能要过好几年才会撤稿。

\n

不过,更大的问题可能是疏忽。科学期刊喜欢发表积极的结果,所以大多数消极的发现永远不会出现在光鲜的期刊上。如果有人进行的实验表明药物 A 与受体 B 结合,他们会发表它——但忽略提及药物 A 不会通过 Z 与受体 C 结合。无效结果很少传给科学家,他们中的许多人已经几个月来一次又一次尝试实验的痛苦经历,后来才发现 1970 年代的一篇不起眼的论文使他们所有的努力都变得毫无意义。

\n

我告诉你这些悲伤的事情——停滞不前的科学和可怕的低效率的故事——是为了说明一个观点:生物学在去年取得了如此大的进步,真是令人惊讶。生物学的进步证明了人类渴望探索、失败,然后继续前进的愿望。这份时事通讯庆祝人类的成就,并重点介绍了过去 12 个月生物学领域的十大进步

\n

此列表中的所有内容均来自 Codon 的上一期,因此希望您能在评论中指出我的错误和遗漏。我的入选标准很简单:该列表仅包括 2022 年期间发布到 bioRxiv 或发表在期刊上的论文。我不包括公司成就——这实际上可能是它自己的列表——除非他们发布了数据。(入选)列表中的一些项目包括了多篇论文,因为整个子领域发展得非常快。

\n

汇总“十佳排名”最大的危险是完全主观的,有很多优秀的东西没有入选,而且很多其他作家已经做到了(虽然我还没有看到专门针对生物学的清单)。诺亚·史密斯 (Noah Smith) 发布了他 2023 年的技术乐观主义清单 (techno-optimism list),其中包括对生物技术的简要提及,而《大西洋月刊》(The Atlantic) 发表了他们的 "年度突破 (breakthroughs of the year)",然后立即将该文章设置为付费文章。

\n

然而,有必要专门为生物学列出一份完整的榜单,因为很多伟大的事情在人工智能的阴影下被忽略了。人类基因组计划(始于 1990 年)终于在今年完成了,一个庞大的科学家团队填补了最后 8% 的序列空白。科学家们还使用 mirror-image DNA 聚合酶制作了镜像 DNA (mirror-image DNA),并发现了一类新的 CRISPR 蛋白质,它们可以剪切蛋白质而不是基因。机器学习正在蛋白质工程中掀起波澜,例如有一种基于算法被设计出来的酶,这种酶可以比自然界中发现的任何酶更快地分解 PET 塑料

\n

我不确定今年的进展是否与生物进展是否整体停滞不前有关。但有一件事是不变的:生物学变得越来越奇怪,而我会一直关注它。

\n

10. 走向合成细胞

\n

从纯化学成分构建合成细胞是生物学的圣杯。如果实现了这一壮举,将证明我们已足够详细地理解生命运作的大体轮廓,并有足够的细节可以在实验室中重现它。这也将成为定制细胞的起点,这些细胞可以检测有毒污染或制造药物,同时又不会成为生物安全风险或存在感染风险。

\n

今年有几篇论文推动了合成细胞的发展,但其中有两篇让人印象深刻。第一篇是在 bioRxiv 上发表的预印本,据称是首次证明核糖体(大分子蛋白质,负责合成其他蛋白质)可以在活细胞之外制造。这是在合成细胞内从头生产蛋白质的重要起点。

\n

我们还在合成细胞分裂方面取得了重要进展。一项研究报告说,仅使用五种蛋白质就可以在脂肪泡中制造合成分裂环!当这些蛋白质聚集在一起时,它们会收缩并向气泡施加力(下面的 GIF)。

\n

\n
\n 合成分裂环在气泡内形成的延时摄影\n

\n

9. 更好的碱基编辑器

\n

早在 2016 年,《自然》杂志的一篇论文就报道了第一个碱基编辑蛋白,它可以将 DNA 中的 "C" 替换为 "T",而无需将基因组一分为二。它的重要性立即显而易见——许多严重的遗传疾病是由 DNA 中的单个碱基交换引起的,现在这些突变可以被修复。

\n

碱基编辑器已经成熟。这些基因编辑蛋白在发明后仅仅五年就以创纪录的速度进入临床试验,目前 Verve、Beam 和其他公司正在进行针对镰状细胞病、高胆固醇和 Stargardt 病的试验

\n

然而,碱基编辑的主要挑战之一是编辑线粒体基因组很棘手,许多遗传疾病都源于此。早在 2020 年,一篇论文就表明碱基编辑器可以成功进入线粒体并使 "C" 变为 "T",但其前景并不乐观。今年 5 月,一篇后续论文称,实际上,这些线粒体基因编辑器诱发了 "大量" 脱靶突变,这意味着它们编辑的位置比预期的要多,弊大于利。

\n

但创新不会因失败而受阻。仅今年一年就至少发表了三篇论文,使线粒体碱基编辑器变得更小更准确。让碱基编辑酶进入线粒体或编辑其 DNA 从未如此简单。我相信我们很快就会看到一些针对线粒体相关疾病的临床试验。

\n

8. 噬菌体传播病毒

\n

今年对噬菌体来说是个好年头。这真的很合适,因为它也是 Felix d\'Herelle 著名实验 100 周年纪念日。1922 年,这位巴黎微生物学家证明噬菌体(感染细菌的小病毒)可以根除兔子和小动物体内的 "痢疾杆菌和其他杆菌"。

\n

我们现在正经历着临床疗法的准复兴时期,噬菌体经常被用来消除抗生素无效的感染(尤其是在欧洲医院)。几周前,一个欧洲科学家团队使用实验性噬菌体疗法挽救了一名幼儿的生命。器官移植后,这个小男孩感染了抗生素无法清除的耐药性感染。在用定制的噬菌体鸡尾酒 (a custom-made phage cocktail) 治疗两年多后,孩子在家中恢复了健康。

\n

5 月,丹佛的一个团队使用噬菌体治疗一名患有严重囊性纤维化的男孩的脓肿分枝杆菌感染。噬菌体将感染控制了一年多,直到获得供体肺。我相信我们会在 2023 年看到定制噬菌体疗法进入临床。

\n

\n
\n

\n

7. 血友病基因疗法

\n

Hemgenix 是一种治疗 B 型血友病的基因疗法,几个月前获得了 FDA 的批准。它的价格达到了 350 万美元,使其成为有史以来最昂贵的药物(这并不好)。根据 III 期临床试验数据,它在患者的是安全有效期至少两年

\n

血友病 A 的基因治疗进展缓慢,该病由一种名为 VIII 的不同凝血蛋白突变引起。5 月的一项研究表明,针对肝脏的基因疗法在非人类灵长类动物中效果很好,可以导致 "总凝血因子 VIII 输出增加 10 倍以上"。3 月份发表的一项有 134 名参与者参与的 I/II 期临床试验表明,使用腺相关病毒进行的基因疗法,也用于肝脏,可减少血友病患者的出血事件。但是,它带来了很多副作用;每个试验参与者至少有一次不良事件。尽管如此,血友病仍是基因治疗的 "低悬" 目标之一,这些试验是其他正在进行中的目标的有用酸性测试。

\n

6. 合成胚胎

\n

今年,从老鼠身上采集的干细胞被用来制造 "类胚胎结构",其中包含工作的肠道、跳动的心脏和头脑的雏形,而不需要精子或卵子。

\n

以色列的 Jacob Hanna 团队发表了一篇最初的论文,于 8 月在 Cell 上发表。据《卫报》报道,这些作者后来成立了一家名为 Renewal Bio 的公司,"旨在培养人类合成胚胎,为医疗条件提供组织和细胞"。剑桥大学和加州理工学院的一个团队也在 8 月 2 日发布了一份预印本,表明这些 "合成胚胎"准确地概括了 "从胚胎第 5.5 天到第 8.5 天的发育事件,包括原肠胚形成、前后轴的形成、大脑,跳动的心脏结构,以及胚胎外组织(包括卵黄囊和绒毛膜)的发育。"

\n

合成胚胎——正确形成的概率只有 0.5% 左右——有几个潜在的用途。例如,这些结构可以用于研究器官在发育过程中的形成,也可用于在不使用真实胚胎的情况下测试药物。

\n

\n
\n Embryoids after six days. From Kasey Lau et al. on bioRxiv. Link\n

\n

5. 细胞重编程

\n

今年的一大亮点:首次证明仅靠化学物质就能将人体细胞重新编程为干细胞。这一突破需要十多年的时间,并需使用 11 种不同的化学物质,以及一到两个月的工作时间,所以仍需要一些微调。早在 2013 年,同一个小组就已使用这种方法实现了小鼠细胞的转化,但人类细胞的转化过程要困难得多。

\n

这也不是第一项重新编程人类细胞的研究。这一荣誉属于山中伸弥 (Shinya Yamanaka),他在 2006 年通过表达四种蛋白质(现在著名的 "Yamanaka 因子")对 iPS 细胞进行了重编程。在随后的几十年中,其他研究小组使用病毒或 mRNA 对细胞进行重编程。但这种仅使用化学物质的方法脱颖而出,因为它在体外使用简单,而且化学混合物可以通过静脉注射输送到体内——不需要基因编辑。该方法提供了一种相对简单的工具来生成可用于再生医学的人类多能干细胞。

\n

4. 植物更容易设计

\n

我们生活在人类世,这是人类历史上一个可怕的时刻,人造材料的重量超过地球上所有的生物量,而且重量每年都在继续增加一倍。

\n

\n
\n "Global human-made mass exceeds all living biomass," by Elhacham E et al. in Nature. Link\n

\n

在我们现有的生物质中,据估计有 83% 由植物持有。如果我们想要走出这场行星垃圾场的困境,那么,那么我们可能不得不对植物进行工程改造:让它们捕获更多的碳,增强它们的光合作用,种植生产更多的食物,等等!

\n

幸运的是,做到这一点从未如此简单。几十年来,合成生物学家已经对细菌和哺乳动物细胞进行了改造,使其具有越来越复杂的遗传回路,即使植物在很大程度上被忽视了。今年,两项重要进展改变了平衡。

\n

先是基因编辑技术,如 CRISPR,现在已经过优化,可以在植物中更好地发挥作用。例如,Prime 编辑器是可以插入、删除或交换 DNA 的 "搜索和替换" 基因编辑器。与其他 Prime 编辑器相比,新的 Plant Prime Editor 在植物细胞中的效率提高了 3.4 倍,并被用于在实验室中迅速使水稻植物对除草剂产生耐受性。

\n

但更大的进步是:斯坦福大学的一个团队发布了一个完整的基因工具包,可以像我们对细菌进行编程一样对植物进行 "编程"。新工具包包括大量合成启动子和转录因子,可用于控制植物中的基因表达。这些遗传部分被用于构建能够在本塞姆氏烟草和拟南芥中进行布尔逻辑运算的基因回路。作者还建立了逻辑门,可以控制植物根部的基因表达水平,从而控制它们的侧向密度。

\n

\n
\n A genetic circuit controls how many lateral roots shoot out from a plant’s roots. Lateral density increases from left to right, with a wildtype plant shown on the far right. From Brophy et al. on bioRxiv.\n

\n

3. 走向负碳

\n

生物学的一个众所周知的困难部分是难以扩展(进行大规模的研究)。在试管中改造一个能将糖转化为抗癌药物的细胞是一回事,但在一个千升生物反应器中做同样的事却是完全不同的挑战。

\n

这就是像 LanzaTech 这样的公司令人兴奋的原因。他们实际上已经在工业工厂扩大了生物学规模。他们有试点设施,将工厂的废碳回收成燃料和化学品。这些工厂每年可以生产数千亿加仑的燃料,并且已经达到相当于每年减少数千辆汽车上路的排放量。

\n

几个月前,来自 LanzaTech 和西北大学的科学家们达到了另一个里程碑:使用一种名为 Clostridium autoethanogenum 的工程自养生物,他们在具有负碳足迹的过程中以工业规模生产丙酮和异丙醇。 "与导致温室气体释放的传统生产过程不同,我们的过程可以固定碳," 他们在发表的论文中写道。这是大规模生物学向前迈出的一大步。经过改造的微生物可以在不拖累大气的情况下改善污染物并产生化学物质。

\n

2. 异种移植成为现实

\n

这将作为 "异种移植年" 载入人类史册。异种移植的历史可以追溯到 20 世纪 60 年代中期——法国外科医生勒内·库斯 (Renè Kuss) 将猪肾移植到人体中,结果很快被患者的身体排斥——异种移植一直是一个失败的领域。最著名的例子可能是 80 年代 Stephanie Beauclair 或 Baby Fae 的手术,她从狒狒那里接受了一颗心脏,但不久后就去世了。

\n

不过,在过去四十年里,我们在从猪身上提取心脏并将其植入人体方面做得更好,因为基因编辑技术正在改进。现在比以往任何时候都更容易在猪的细胞中找到所有导致我们的身体排斥该器官的有害蛋白质,并从基因组中系统地消除这些蛋白质编码基因。但进步从来都不是没有陷阱的。

\n

今年 1 月 7 日,马里兰大学的一组外科医生将一颗猪的心脏移植到 57 岁的老大卫贝内特体内,两个月后他去世了。

\n

5 月,两只猪的肾脏被移植到脑死亡患者体内,并进行了 54 小时的监测,这让沮丧过后变得乐观起来。两个肾脏都产生了尿液,活组织检查没有显示出任何器官排斥的迹象。

\n

心脏移植可能因为器官感染了猪病毒而失败,但肾移植研究的作者没有检测到这种病毒。猪肾可能很快就会进入人们的生活。

\n

1. 我们离终结疟疾从未如此近

\n

如果您相信约翰·惠特菲尔德 (John Whitfield) 2002 年在《自然》杂志发表的这篇文章(该说法未被引用),"疟疾已经杀死了所有曾经生活过的人的一半"。即使该说法是错误的,在整个人类历史上,蚊子也已经集体杀死了数十亿人。昆虫混蛋干掉了亚历山大大帝、哥特人阿拉里克和但丁。而且,在 2021 年,疟疾仍导致约 620,000 人死亡。这是令人震惊、悲伤和可以预防的。但今年是取得惊人进步的一年。

\n

一种称为 R21/Matrix-M 的疟疾疫苗在四个非洲国家进行了 III 期试验。它在幼儿中的总体疗效为 75%。这是个好消息。在马里进行的一项 II 期试验还测试了一种名为 CIS43LS 的抗体,用于对抗健康成人中的恶性疟原虫感染。在六个月的时间里,单次注射的疗效为 88.2%

\n

不过,唯一能有效预防疟疾 90% 以上的免疫原是子孢子,这是一种在蚊子生命周期中形成的类孢子部分。这些子孢子被注射到手臂中并用作疫苗,但显然很难从真正的蚊子身上收集到这些东西。

\n

本月早些时候,研究人员在实验室中创造了 "数亿" 子孢子,而不需要蚊子。他们基本上重新创建了整个"疟原虫从传染性配子体到传染性配子体的全部生命周期,而不需要蚊子。" 这项新技术将有助于更快、更便宜地研制出抗疟疾疫苗。

\n

\n
\n

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.3-资讯'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '那些年,和微信公众号编辑器战斗的日子', 'number': 31, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/31', 'createdAt': '2023-12-01T03:10:07Z', 'lastEditedAt': '2023-12-01T05:35:04Z', 'updatedAt': '2024-01-04T05:44:14Z', 'body': "看到 HelloGitHub 公众号在 2019-09-25 发表的这篇文章《[和微信公众号编辑器战斗的日子](https://mp.weixin.qq.com/s/3-A_iSZYD88Cy467qOnNOw)》,结合自己最近折腾的 React 版本应用 [Markdown2Html](https://github.com/shenweiyan/Markdown2Html),也想着来聊几句。\r\n\r\n\r\n\r\n## Md2All\r\n\r\n在使用 Mdnice 前,一直在用 [Md2All](https://md.aclickall.com) 的自搭建版本 [Md2XEditor](https://github.com/shenweiyan/Md2XEditor),这是一个源自 [barretlee](https://github.com/barretlee) 最早在 2017 年的 [online-markdown](https://github.com/barretlee/online-markdown) 项目,经过二次开发而来的 Markdown 在线转换工具。\r\n\r\n个人在 2021 年的时候,浏览 GitHub 无意中发现了 [Md2All](https://md.aclickall.com) 托管在 GitHub 的源码仓库 [github.com/aclickall/aclickall.github.io](https://github.com/aclickall/aclickall.github.io>),Fork 过来,利用自己微薄的前端知识做了一点点修改,才形成了一直使用到今天的 [Md2XEditor](https://github.com/shenweiyan/Md2XEditor)。 \r\n![Md2XEditor v-2.8.5](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/md2xeditor-v2.8.5.png)\r\n\r\n虽然说,Md2All 已经把 Markdown2Html 或者说把 Markdown2WeChat 的大部分功能实现了,但由于它目前能找到的源码都是 **经过 build 构建后可以在生产环境中使用的最终版本的代码**(诸如压缩和优化代码、打包文件、生成静态文件等),功能调整实在太费劲,而且自己对 Node/React 的开发基本是零基础。在没有找到好的替代品前,也只能将就着用,一直用到了 2023 年。\r\n\r\n## markdown-nice\r\n\r\n[Mdnice](https://github.com/mdnice/markdown-nice/) 的项目虽然很早就听说,也曾经试用过一段时间,但是由于收费,加上同样存在 **超链接文字复制到公众号颜色失效** 的问题,所以一直没有深入了解和使用。直到 2023 年下半年看到不少在关注的公众号推文都变换了风格,才知道原来都在用着 Mdnice,于是重新回来一看,发现这个应用原来还是**开源的**,还可以**自己搭建和部署**!\r\n\r\n回来搜了一波 Mdnice,发现 UI 都大同小异,但也发现了 这一个长得很像 Mdnice 又不完全像的平台,从功能和 UI 上它似乎更符合个人的需求和审美,于是去搜源码,果然在 [github.com/TaleAi/markdown2html](https://github.com/TaleAi/markdown2html) 上找到了(虽然这个仓库里面包括 README 在内提供的链接已经失效),但还是果断 Fork 过来,开始了自己部署和折腾之旅。 \r\n![wechat-bmpi-dev](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/wechat-bmpi-dev.png)\r\n\r\n## 一点折腾\r\n\r\n把自己的 Markdown2Html 站点部署起来后,一切看起来都很顺利,但在使用过程中就发现了这个一直存在的问题:**超链接文字复制到公众号颜色失效**!\r\n\r\n于是开始去尝试看看 Mdnice 的源码,从最开始的一头雾水开始到慢慢摸到一点点头绪,也第一次知道了 [markdown-it](https://github.com/markdown-it/markdown-it) 这个目前使用最广泛的 markdown 解析器工具。但功夫不负有心人,借助 ChatGPT 的帮助,最后终于勉勉强强把 **超链接文字复制到公众号颜色失效** 给解决了。\r\n\r\n后面还陆陆续续增加了一些自己喜欢的文章主题,增加了一些网格化的背景等等。由于 Mdnice 使用了非常多的开源插件,所以很多东西改动起来都非常方便。 \r\n![markdown2weixin](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/markdown2wechat.png)\r\n\r\n## 继续更新\r\n\r\n个人 (包括本公众号) 很多的文章都是先写在 GitHub [Knowledge-Garden](https://github.com/shenweiyan/Knowledge-Garden) 仓库的 [Discussions](https://github.com/shenweiyan/Knowledge-Garden/discussions) 上,有了 Markdown2Html 后面想要转到公众号也就很方便了。\r\n\r\n到这里,轮子也总算造完了,又该好好搬砖了。\r\n\r\n希望后面能有更多的东西跟大家分享吧,也希望大家在 GitHub 上多多关注我,一起交流。\r\n\r\n## 参考资料\r\n\r\n1. [Markdown-It 解析原理](https://lq782655835.github.io/blogs/project/markdown-it-code.html) - [springleo's blog](https://lq782655835.github.io/blogs/)", 'bodyText': "看到 HelloGitHub 公众号在 2019-09-25 发表的这篇文章《和微信公众号编辑器战斗的日子》,结合自己最近折腾的 React 版本应用 Markdown2Html,也想着来聊几句。\n\nMd2All\n在使用 Mdnice 前,一直在用 Md2All 的自搭建版本 Md2XEditor,这是一个源自 barretlee 最早在 2017 年的 online-markdown 项目,经过二次开发而来的 Markdown 在线转换工具。\n个人在 2021 年的时候,浏览 GitHub 无意中发现了 Md2All 托管在 GitHub 的源码仓库 github.com/aclickall/aclickall.github.io,Fork 过来,利用自己微薄的前端知识做了一点点修改,才形成了一直使用到今天的 Md2XEditor。\n\n虽然说,Md2All 已经把 Markdown2Html 或者说把 Markdown2WeChat 的大部分功能实现了,但由于它目前能找到的源码都是 经过 build 构建后可以在生产环境中使用的最终版本的代码(诸如压缩和优化代码、打包文件、生成静态文件等),功能调整实在太费劲,而且自己对 Node/React 的开发基本是零基础。在没有找到好的替代品前,也只能将就着用,一直用到了 2023 年。\nmarkdown-nice\nMdnice 的项目虽然很早就听说,也曾经试用过一段时间,但是由于收费,加上同样存在 超链接文字复制到公众号颜色失效 的问题,所以一直没有深入了解和使用。直到 2023 年下半年看到不少在关注的公众号推文都变换了风格,才知道原来都在用着 Mdnice,于是重新回来一看,发现这个应用原来还是开源的,还可以自己搭建和部署!\n回来搜了一波 Mdnice,发现 UI 都大同小异,但也发现了 https://wechat.bmpi.dev/ 这一个长得很像 Mdnice 又不完全像的平台,从功能和 UI 上它似乎更符合个人的需求和审美,于是去搜源码,果然在 github.com/TaleAi/markdown2html 上找到了(虽然这个仓库里面包括 README 在内提供的链接已经失效),但还是果断 Fork 过来,开始了自己部署和折腾之旅。\n\n一点折腾\n把自己的 Markdown2Html 站点部署起来后,一切看起来都很顺利,但在使用过程中就发现了这个一直存在的问题:超链接文字复制到公众号颜色失效!\n于是开始去尝试看看 Mdnice 的源码,从最开始的一头雾水开始到慢慢摸到一点点头绪,也第一次知道了 markdown-it 这个目前使用最广泛的 markdown 解析器工具。但功夫不负有心人,借助 ChatGPT 的帮助,最后终于勉勉强强把 超链接文字复制到公众号颜色失效 给解决了。\n后面还陆陆续续增加了一些自己喜欢的文章主题,增加了一些网格化的背景等等。由于 Mdnice 使用了非常多的开源插件,所以很多东西改动起来都非常方便。\n\n继续更新\n个人 (包括本公众号) 很多的文章都是先写在 GitHub Knowledge-Garden 仓库的 Discussions 上,有了 Markdown2Html 后面想要转到公众号也就很方便了。\n到这里,轮子也总算造完了,又该好好搬砖了。\n希望后面能有更多的东西跟大家分享吧,也希望大家在 GitHub 上多多关注我,一起交流。\n参考资料\n\nMarkdown-It 解析原理 - springleo's blog", 'bodyHTML': '

看到 HelloGitHub 公众号在 2019-09-25 发表的这篇文章《和微信公众号编辑器战斗的日子》,结合自己最近折腾的 React 版本应用 Markdown2Html,也想着来聊几句。

\n\n

Md2All

\n

在使用 Mdnice 前,一直在用 Md2All 的自搭建版本 Md2XEditor,这是一个源自 barretlee 最早在 2017 年的 online-markdown 项目,经过二次开发而来的 Markdown 在线转换工具。

\n

个人在 2021 年的时候,浏览 GitHub 无意中发现了 Md2All 托管在 GitHub 的源码仓库 github.com/aclickall/aclickall.github.io,Fork 过来,利用自己微薄的前端知识做了一点点修改,才形成了一直使用到今天的 Md2XEditor
\nMd2XEditor v-2.8.5

\n

虽然说,Md2All 已经把 Markdown2Html 或者说把 Markdown2WeChat 的大部分功能实现了,但由于它目前能找到的源码都是 经过 build 构建后可以在生产环境中使用的最终版本的代码(诸如压缩和优化代码、打包文件、生成静态文件等),功能调整实在太费劲,而且自己对 Node/React 的开发基本是零基础。在没有找到好的替代品前,也只能将就着用,一直用到了 2023 年。

\n

markdown-nice

\n

Mdnice 的项目虽然很早就听说,也曾经试用过一段时间,但是由于收费,加上同样存在 超链接文字复制到公众号颜色失效 的问题,所以一直没有深入了解和使用。直到 2023 年下半年看到不少在关注的公众号推文都变换了风格,才知道原来都在用着 Mdnice,于是重新回来一看,发现这个应用原来还是开源的,还可以自己搭建和部署

\n

回来搜了一波 Mdnice,发现 UI 都大同小异,但也发现了 https://wechat.bmpi.dev/ 这一个长得很像 Mdnice 又不完全像的平台,从功能和 UI 上它似乎更符合个人的需求和审美,于是去搜源码,果然在 github.com/TaleAi/markdown2html 上找到了(虽然这个仓库里面包括 README 在内提供的链接已经失效),但还是果断 Fork 过来,开始了自己部署和折腾之旅。
\nwechat-bmpi-dev

\n

一点折腾

\n

把自己的 Markdown2Html 站点部署起来后,一切看起来都很顺利,但在使用过程中就发现了这个一直存在的问题:超链接文字复制到公众号颜色失效

\n

于是开始去尝试看看 Mdnice 的源码,从最开始的一头雾水开始到慢慢摸到一点点头绪,也第一次知道了 markdown-it 这个目前使用最广泛的 markdown 解析器工具。但功夫不负有心人,借助 ChatGPT 的帮助,最后终于勉勉强强把 超链接文字复制到公众号颜色失效 给解决了。

\n

后面还陆陆续续增加了一些自己喜欢的文章主题,增加了一些网格化的背景等等。由于 Mdnice 使用了非常多的开源插件,所以很多东西改动起来都非常方便。
\nmarkdown2weixin

\n

继续更新

\n

个人 (包括本公众号) 很多的文章都是先写在 GitHub Knowledge-Garden 仓库的 Discussions 上,有了 Markdown2Html 后面想要转到公众号也就很方便了。

\n

到这里,轮子也总算造完了,又该好好搬砖了。

\n

希望后面能有更多的东西跟大家分享吧,也希望大家在 GitHub 上多多关注我,一起交流。

\n

参考资料

\n
    \n
  1. Markdown-It 解析原理 - springleo\'s blog
  2. \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '单行 Python 代码片段', 'number': 30, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/30', 'createdAt': '2023-12-01T03:05:46Z', 'lastEditedAt': None, 'updatedAt': '2024-01-03T07:56:51Z', 'body': '> Via:https://muhammadraza.me/2023/python-oneliners\r\n\r\n我已经沉浸在 Python 编程世界大约三年了。在这段时间里,我开始欣赏这种多功能语言的优雅和强大。在这篇既有趣又具有教育意义的文章中,我将展示一系列单行 Python 代码片段。无论您是经验丰富的开发人员还是初学者,这些简洁的代码行都可以让您深入了解 Python 的简单性和有效性,它们展示一行代码如何完成在其他语言中可能需要几行代码才能完成的任务。\r\n\r\n\r\n\r\n- 反转字符串\r\n```python\r\nreversed_string = "Hello World"[::-1]\r\n```\r\n\r\n- 检查数字是否为偶数\r\n```python\r\nis_even = lambda x: x % 2 == 0\r\nis_even(8) #True\r\n```\r\n\r\n- 求两个列表的交集\r\n```python\r\nintersection = list(set(list1) & set(list2))\r\n```\r\n\r\n- 从列表中删除重复项\r\n```python\r\nno_duplicates = list(set(my_list))\r\n```\r\n\r\n- 不使用 `len()` 计算字符串的长度\r\n```python\r\nlength = sum(1 for _ in \'Hello World\')\r\n```\r\n\r\n- 检查一个列表是否包含另一个列表的所有元素\r\n```python\r\ncontains_all = all(elem in list1 for elem in list2)\r\n```\r\n\r\n- 生成一串随机字符\r\n```python\r\nimport random; \r\nrandom_str = \'\'.join(random.choices(\'abcdefghijklmnopqrstuvwxyz\', k=10))\r\n```\r\n\r\n- 将整数列表转换为单个数字\r\n```python\r\nnum = int(\'\'.join(map(str, [1, 2, 3, 4, 5])))\r\n```\r\n\r\n- 回文(Palindromic)检查\r\n```python\r\nis_palindrome = lambda s: s == s[::-1]\r\n```\r\n\r\n- 列表展开\r\n```python\r\nflatten_list = sum([[1, 2], [3, 4]], [])\r\n```\r\n\r\n- 在一个列表中找到出现频率最高的元素\r\n```python\r\nmost_frequent = max(set(my_list), key=my_list.count)\r\n```\r\n\r\n- 合并两个字典\r\n```python\r\nmerged_dict = {**dict1, **dict2}\r\n```\r\n\r\n最后,我希望您喜欢阅读本文并有机会学习新东西。如果您有任何反馈,请随时在下面发表评论。如果您不想公开发表评论,可以随时给我发送电子邮件。我也很想看到你最喜欢的 python one liner 代码片段。', 'bodyText': 'Via:https://muhammadraza.me/2023/python-oneliners\n\n我已经沉浸在 Python 编程世界大约三年了。在这段时间里,我开始欣赏这种多功能语言的优雅和强大。在这篇既有趣又具有教育意义的文章中,我将展示一系列单行 Python 代码片段。无论您是经验丰富的开发人员还是初学者,这些简洁的代码行都可以让您深入了解 Python 的简单性和有效性,它们展示一行代码如何完成在其他语言中可能需要几行代码才能完成的任务。\n\n\n反转字符串\n\nreversed_string = "Hello World"[::-1]\n\n检查数字是否为偶数\n\nis_even = lambda x: x % 2 == 0\nis_even(8) #True\n\n求两个列表的交集\n\nintersection = list(set(list1) & set(list2))\n\n从列表中删除重复项\n\nno_duplicates = list(set(my_list))\n\n不使用 len() 计算字符串的长度\n\nlength = sum(1 for _ in \'Hello World\')\n\n检查一个列表是否包含另一个列表的所有元素\n\ncontains_all = all(elem in list1 for elem in list2)\n\n生成一串随机字符\n\nimport random; \nrandom_str = \'\'.join(random.choices(\'abcdefghijklmnopqrstuvwxyz\', k=10))\n\n将整数列表转换为单个数字\n\nnum = int(\'\'.join(map(str, [1, 2, 3, 4, 5])))\n\n回文(Palindromic)检查\n\nis_palindrome = lambda s: s == s[::-1]\n\n列表展开\n\nflatten_list = sum([[1, 2], [3, 4]], [])\n\n在一个列表中找到出现频率最高的元素\n\nmost_frequent = max(set(my_list), key=my_list.count)\n\n合并两个字典\n\nmerged_dict = {**dict1, **dict2}\n最后,我希望您喜欢阅读本文并有机会学习新东西。如果您有任何反馈,请随时在下面发表评论。如果您不想公开发表评论,可以随时给我发送电子邮件。我也很想看到你最喜欢的 python one liner 代码片段。', 'bodyHTML': '
\n

Via:https://muhammadraza.me/2023/python-oneliners

\n
\n

我已经沉浸在 Python 编程世界大约三年了。在这段时间里,我开始欣赏这种多功能语言的优雅和强大。在这篇既有趣又具有教育意义的文章中,我将展示一系列单行 Python 代码片段。无论您是经验丰富的开发人员还是初学者,这些简洁的代码行都可以让您深入了解 Python 的简单性和有效性,它们展示一行代码如何完成在其他语言中可能需要几行代码才能完成的任务。

\n\n
    \n
  • 反转字符串
  • \n
\n
reversed_string = "Hello World"[::-1]
\n
    \n
  • 检查数字是否为偶数
  • \n
\n
is_even = lambda x: x % 2 == 0\nis_even(8)  #True
\n
    \n
  • 求两个列表的交集
  • \n
\n
intersection = list(set(list1) & set(list2))
\n
    \n
  • 从列表中删除重复项
  • \n
\n
no_duplicates = list(set(my_list))
\n
    \n
  • 不使用 len() 计算字符串的长度
  • \n
\n
length = sum(1 for _ in \'Hello World\')
\n
    \n
  • 检查一个列表是否包含另一个列表的所有元素
  • \n
\n
contains_all = all(elem in list1 for elem in list2)
\n
    \n
  • 生成一串随机字符
  • \n
\n
import random; \nrandom_str = \'\'.join(random.choices(\'abcdefghijklmnopqrstuvwxyz\', k=10))
\n
    \n
  • 将整数列表转换为单个数字
  • \n
\n
num = int(\'\'.join(map(str, [1, 2, 3, 4, 5])))
\n
    \n
  • 回文(Palindromic)检查
  • \n
\n
is_palindrome = lambda s: s == s[::-1]
\n
    \n
  • 列表展开
  • \n
\n
flatten_list = sum([[1, 2], [3, 4]], [])
\n
    \n
  • 在一个列表中找到出现频率最高的元素
  • \n
\n
most_frequent = max(set(my_list), key=my_list.count)
\n
    \n
  • 合并两个字典
  • \n
\n
merged_dict = {**dict1, **dict2}
\n

最后,我希望您喜欢阅读本文并有机会学习新东西。如果您有任何反馈,请随时在下面发表评论。如果您不想公开发表评论,可以随时给我发送电子邮件。我也很想看到你最喜欢的 python one liner 代码片段。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.2-编程'}, 'labels': {'nodes': [{'name': '翻译'}, {'name': '1.2.3-Python'}]}, 'comments': {'nodes': []}}, {'title': '技术人月刊(第 1 期 2023-12)', 'number': 29, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/29', 'createdAt': '2023-12-01T02:57:46Z', 'lastEditedAt': '2023-12-20T03:32:00Z', 'updatedAt': '2023-12-20T03:32:00Z', 'body': '个人的信息周刊,每月记录我看到的有价值的信息,主要针对生物学和互联网科技领域,内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。\r\n\r\n## 工具\r\n\r\n1. [通过人工智能将表情符号变成令人惊叹的艺术品](https://github.com/leptonai/tryemoji)\r\n\r\n

\r\n\r\nGitHub 上的一个开源项目,包括了完整的前端和后端代码,支持本地和云端部署,可用于商业用途。\r\n\r\n2. [pdf2htmlEX](https://github.com/pdf2htmlEX/pdf2htmlEX)\r\n\r\n

\r\n

\r\n\r\n一个 PDF 转 HTML 程序,生成的结果和原始 PDF 几乎一模一样。其背后是利用的 Chrome Headless,让 Chrome 渲染 PDF,再导出成 HTML,甚至图片都转成了 base64 字符,所以一个网页就可以包含完整的文本、字体和图片等内容。\r\n\r\n3. [Quartz](https://github.com/jackyzha0/quartz)\r\n\r\nQuartz 是一套可帮助您免费将数字花园和笔记发布为网站的工具。Quartz v4 进行了彻底重写,重点关注最终用户的可扩展性和易用性。该工具可直接把 obsidian 笔记部署到线上,可以认为是 Obsidian Publish 功能的替代品,但是是免费的。不仅是 Obsidian 笔记,任何 markdown 双链笔记都可以部署。\r\n\r\n4. [gkd](https://github.com/gkd-kit/gkd)\r\n\r\n李跳跳被禁用后的一个替代品,基于高级选择器 + 订阅规则 + 快照审查,它可以实现点击跳过任意开屏广告/点击关闭应用内部任意弹窗广告, 如关闭百度贴吧帖子广告卡片/知乎回答底部推荐广告卡片。\r\n\r\n5. [Blossom](https://github.com/blossom-editor/blossom)\r\n\r\nBlossom 是一个支持私有部署的云端存储双链笔记软件,你可以将你所有的笔记,图片,个人计划安排保存在自己的服务器中,并在任意设备之间实时同步,且基于MIT协议完全开源。UI 非常漂亮的一款云端双链笔记。 \r\n\r\n\r\n6. [MDX Editor](https://editor.runjs.cool/) - 跨平台微信排版Markdown编辑器\r\n\r\nmdx 是 markdown + jsx 的结合,即可以支持 markdown 语法也可以写自定义组件。\r\n\r\n支持一键复制到微信公众号、自定义样式组件,样式、生成二维码、代码 diff 高亮、生成文章,软件还支持本地文件实时保存、文件目录树管理和导出 HTML。 \r\n![mdx-editor](https://shub.weiyan.tech/kgarden/2023/mdx-editor.png)\r\n\r\n## 文章\r\n\r\n1. [Cloudflare 发布了 2023 年度回顾](https://blog.cloudflare.com/radar-2023-year-in-review/)\r\n\r\n2023 年 Cloudflare Radar [#YearInReview](https://twitter.com/hashtag/YearInReview?src=hashtag_click) 是 Cloudflare 对全年在全球和国家/地区层面观察到的各种流量、连接性和速度指标的互联网趋势和模式的第四次年度回顾。\r\n\r\n## 资源\r\n\r\n1. [你用 Python 做过的最酷的事情是什么?](https://www.reddit.com/r/Python/comments/17upt2f/whats_the_coolest_things_youve_done_with_python/)\r\n\r\nreddit 上很火的一个讨论,让人大开眼界。\r\n\r\n3. [Data Hacks](https://data-hacks.com/)\r\n\r\n一个关于如何处理数据的网站,其中包含 1000 个快速 R 和 Python 教程。在这个网站上,您将会找到关于数据科学和统计学领域各种主题的 R 编程和 Python 编程指南。\r\n\r\n4. [哪个是程序员最爱的编程字体?2百万阅读的帖子选出最帅的七种字体](https://vikingz.me/best-font/)\r\n\r\n最后根据评论选出几款最受欢迎的供大家参考:Consolas,最多人推荐;JetBrains Mono 更推荐它的魔改版本 Jetbrains Mono Nerd Font;SF Mono,同样也有魔改版本 SFMono Nerd Font Ligaturized。\r\n\r\n5. [大规模语言模型:从理论到实践](https://intro-llm.github.io/)\r\n\r\n复旦大学张奇教授团队写的一本在线免费的电子书,《大规模语言模型:从理论到实践》,大概有 300 页篇幅,将大模型从理论到实战的每个阶段都描述的较为清楚。\r\n\r\n6. 《[Python 工匠](https://github.com/piglei/one-python-craftsman)》\r\n\r\n它专注于分享 Python 编程中的一些偏「小」的东西,例如变量和注释的使用、编写条件分支的技巧、编写跑的更快扩展性更好的代码,让函数反馈结果的技巧、异常处理的好习惯、装饰器的使用技巧等等。\r\n

one-python-craftsman

\r\n\r\n7. 《[Python Cookbook in Chinese](https://python3-cookbook.readthedocs.io/zh-cn/latest/index.html)》 3rd Edition\r\n

\r\n\r\n## 图片\r\n\r\n1. [世界上 14 座最伟大的宗教建筑](https://twitter.com/culturaltutor/status/1728746068324631017)\r\n\r\n来源于推特的信息,对于排名和入选不少网友表示怀疑,但的确很震撼。\r\n\r\n一. 日本京都金阁寺\r\n\r\n金阁寺(“金阁寺”)曾经是邪恶幕府将军的私人住宅,后来被他的儿子改建为禅宗佛教寺庙。 \r\n那是600年前的事了。它在 20 世纪 50 年代被一位和尚烧毁,并逐梁重建。\r\n\r\n\r\n二. 英国达勒姆大教堂\r\n\r\n英国最精美的诺曼大教堂,以其巨大的 11 世纪鼓柱和坚固的塔楼仍然占据着达勒姆市的主导地位。 \r\n现在它和一千年前一样庞大,仍然是卡斯伯特和贝德坟墓的所在地。 \r\n\r\n\r\n\r\n三. 哈尔格林姆教堂,雷克雅未克,冰岛\r\n\r\n世界上最伟大的现代主义教堂之一,将哥特式原则融入现代混凝土和钢材材料中。 \r\n一个富有表现力、迷人、近乎神奇的传统与现代结合的象征。 \r\n\r\n\r\n四. 印度北阿坎德邦 Gurdwara Sri Hemkund Sahib\r\n\r\n有时,让一座建筑变得如此非凡的不仅仅是建筑,还有它的位置。 \r\n位于喜马拉雅山 Garhwal 近 5,000 米高的 Gurdwara Sri Hemkund Sahib 也是如此。 \r\n\r\n\r\n\r\n\r\n五. 匈牙利塞格德犹太教堂\r\n\r\n这是一件不拘一格的杰作,由 Lipót Baumhorn 于 1902 年设计,充满了彩色玻璃和锻铁。 \r\n新艺术风格、新哥特式、新罗马式和新摩尔式建筑融合成一个建筑仙境。 \r\n\r\n\r\n\r\n\r\n六. 迪尔瓦拉耆那教寺庙,印度拉贾斯坦邦\r\n\r\n这座寺庙建于 11 世纪至 16 世纪,历时五百年,也许是索兰基风格建筑的最佳典范。 \r\n精心雕刻的雪白大理石的聚宝盆。 \r\n\r\n\r\n\r\n\r\n七. 保加利亚索非亚亚历山大涅夫斯基大教堂\r\n\r\n一座新拜占庭式建筑的纪念碑,经过三十年的建造,也许是保加利亚脱离奥斯曼帝国独立的顶峰。 \r\n外面有金色和绿色的圆顶瀑布;里面有一个阴暗的洞穴,里面有蜡烛和图标。 \r\n\r\n\r\n八. 叙利亚大马士革大清真寺\r\n\r\n世界上最伟大的建筑之一。这座拥有 4,000 年历史的礼拜场所,在这座从倭马亚王朝到奥斯曼帝国一次又一次改建的杰作的金色马赛克中,仍能看到腓尼基、罗马和早期基督教的遗迹。\r\n\r\n\r\n\r\n\r\n\r\n九. 希腊德尔斐阿波罗神庙\r\n\r\n曾经是古代世界最神圣的地方之一,是德尔斐神谕的故乡,也是所有希腊人的圣地。 \r\n尽管这座寺庙现已成为废墟,但其独特的神秘色彩依然存在,它拥有近 3,000 年的历史,位于帕纳苏斯山的高处。 \r\n\r\n\r\n十. 阿布辛贝,埃及\r\n\r\n一座古埃及神庙,由法老拉美西斯二世建造,旨在荣耀法老拉美西斯二世,成为尼罗河上神一般的永恒哨兵。 \r\n它在沙子下消失了两千多年,被挖掘出来,然后在建造阿斯旺大坝时,一块一块地移动。 \r\n\r\n\r\n\r\n\r\n十一. 科特迪瓦亚穆苏克罗和平圣母大教堂\r\n\r\n一座建于 20 世纪 80 年代的大教堂,令人难以置信。它的灵感来自罗马圣彼得大教堂,但并非直接模仿。据一些人说,它是世界上最大的教堂。 \r\n\r\n\r\n十二. 帕拉蒂纳无伴奏合唱团,巴勒莫,西西里岛\r\n\r\n许多建筑都被认为是独一无二的——这座建筑确实如此。前所未有的拜占庭式、诺曼式和法蒂玛式建筑矩阵;三种宗教和三种风格的结合。穆卡纳斯、半圆顶、圣像、圆形和尖形拱门……独一无二。 \r\n\r\n\r\n\r\n\r\n十三. 贵州梵净山寺庙,中国\r\n\r\n这两座佛教寺庙坐落在武陵山脉深处的岩石上,其历史可以追溯到几个世纪前,看起来几乎是不可能的。 \r\n但它们是真实存在的 — 它们的瓦片由于极端的风力而采用了铁质制作! \r\n\r\n\r\n十四. 印度泰米尔纳德邦米纳克希神庙\r\n\r\n这座庞大的建筑群有着悠久的历史,可以追溯到 1,000 多年前。它是德拉威建筑的一个令人惊叹的典范,拥有 14 座门楼(仪式性入口塔楼),其中一些具有纪念意义,覆盖着精美的彩色雕塑。 \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n', 'bodyText': '个人的信息周刊,每月记录我看到的有价值的信息,主要针对生物学和互联网科技领域,内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。\n工具\n\n通过人工智能将表情符号变成令人惊叹的艺术品\n\n\nGitHub 上的一个开源项目,包括了完整的前端和后端代码,支持本地和云端部署,可用于商业用途。\n\npdf2htmlEX\n\n\n\n一个 PDF 转 HTML 程序,生成的结果和原始 PDF 几乎一模一样。其背后是利用的 Chrome Headless,让 Chrome 渲染 PDF,再导出成 HTML,甚至图片都转成了 base64 字符,所以一个网页就可以包含完整的文本、字体和图片等内容。\n\nQuartz\n\nQuartz 是一套可帮助您免费将数字花园和笔记发布为网站的工具。Quartz v4 进行了彻底重写,重点关注最终用户的可扩展性和易用性。该工具可直接把 obsidian 笔记部署到线上,可以认为是 Obsidian Publish 功能的替代品,但是是免费的。不仅是 Obsidian 笔记,任何 markdown 双链笔记都可以部署。\n\ngkd\n\n李跳跳被禁用后的一个替代品,基于高级选择器 + 订阅规则 + 快照审查,它可以实现点击跳过任意开屏广告/点击关闭应用内部任意弹窗广告, 如关闭百度贴吧帖子广告卡片/知乎回答底部推荐广告卡片。\n\nBlossom\n\nBlossom 是一个支持私有部署的云端存储双链笔记软件,你可以将你所有的笔记,图片,个人计划安排保存在自己的服务器中,并在任意设备之间实时同步,且基于MIT协议完全开源。UI 非常漂亮的一款云端双链笔记。\n\n\nMDX Editor - 跨平台微信排版Markdown编辑器\n\nmdx 是 markdown + jsx 的结合,即可以支持 markdown 语法也可以写自定义组件。\n支持一键复制到微信公众号、自定义样式组件,样式、生成二维码、代码 diff 高亮、生成文章,软件还支持本地文件实时保存、文件目录树管理和导出 HTML。\n\n文章\n\nCloudflare 发布了 2023 年度回顾\n\n2023 年 Cloudflare Radar #YearInReview 是 Cloudflare 对全年在全球和国家/地区层面观察到的各种流量、连接性和速度指标的互联网趋势和模式的第四次年度回顾。\n资源\n\n你用 Python 做过的最酷的事情是什么?\n\nreddit 上很火的一个讨论,让人大开眼界。\n\nData Hacks\n\n一个关于如何处理数据的网站,其中包含 1000 个快速 R 和 Python 教程。在这个网站上,您将会找到关于数据科学和统计学领域各种主题的 R 编程和 Python 编程指南。\n\n哪个是程序员最爱的编程字体?2百万阅读的帖子选出最帅的七种字体\n\n最后根据评论选出几款最受欢迎的供大家参考:Consolas,最多人推荐;JetBrains Mono 更推荐它的魔改版本 Jetbrains Mono Nerd Font;SF Mono,同样也有魔改版本 SFMono Nerd Font Ligaturized。\n\n大规模语言模型:从理论到实践\n\n复旦大学张奇教授团队写的一本在线免费的电子书,《大规模语言模型:从理论到实践》,大概有 300 页篇幅,将大模型从理论到实战的每个阶段都描述的较为清楚。\n\n《Python 工匠》\n\n它专注于分享 Python 编程中的一些偏「小」的东西,例如变量和注释的使用、编写条件分支的技巧、编写跑的更快扩展性更好的代码,让函数反馈结果的技巧、异常处理的好习惯、装饰器的使用技巧等等。\n\n\n《Python Cookbook in Chinese》 3rd Edition\n\n\n图片\n\n世界上 14 座最伟大的宗教建筑\n\n来源于推特的信息,对于排名和入选不少网友表示怀疑,但的确很震撼。\n一. 日本京都金阁寺\n金阁寺(“金阁寺”)曾经是邪恶幕府将军的私人住宅,后来被他的儿子改建为禅宗佛教寺庙。\n那是600年前的事了。它在 20 世纪 50 年代被一位和尚烧毁,并逐梁重建。\n\n二. 英国达勒姆大教堂\n英国最精美的诺曼大教堂,以其巨大的 11 世纪鼓柱和坚固的塔楼仍然占据着达勒姆市的主导地位。\n现在它和一千年前一样庞大,仍然是卡斯伯特和贝德坟墓的所在地。\n\n\n三. 哈尔格林姆教堂,雷克雅未克,冰岛\n世界上最伟大的现代主义教堂之一,将哥特式原则融入现代混凝土和钢材材料中。\n一个富有表现力、迷人、近乎神奇的传统与现代结合的象征。\n\n四. 印度北阿坎德邦 Gurdwara Sri Hemkund Sahib\n有时,让一座建筑变得如此非凡的不仅仅是建筑,还有它的位置。\n位于喜马拉雅山 Garhwal 近 5,000 米高的 Gurdwara Sri Hemkund Sahib 也是如此。\n\n\n\n五. 匈牙利塞格德犹太教堂\n这是一件不拘一格的杰作,由 Lipót Baumhorn 于 1902 年设计,充满了彩色玻璃和锻铁。\n新艺术风格、新哥特式、新罗马式和新摩尔式建筑融合成一个建筑仙境。\n\n\n\n六. 迪尔瓦拉耆那教寺庙,印度拉贾斯坦邦\n这座寺庙建于 11 世纪至 16 世纪,历时五百年,也许是索兰基风格建筑的最佳典范。\n精心雕刻的雪白大理石的聚宝盆。\n\n\n\n七. 保加利亚索非亚亚历山大涅夫斯基大教堂\n一座新拜占庭式建筑的纪念碑,经过三十年的建造,也许是保加利亚脱离奥斯曼帝国独立的顶峰。\n外面有金色和绿色的圆顶瀑布;里面有一个阴暗的洞穴,里面有蜡烛和图标。\n\n八. 叙利亚大马士革大清真寺\n世界上最伟大的建筑之一。这座拥有 4,000 年历史的礼拜场所,在这座从倭马亚王朝到奥斯曼帝国一次又一次改建的杰作的金色马赛克中,仍能看到腓尼基、罗马和早期基督教的遗迹。\n\n\n\n\n九. 希腊德尔斐阿波罗神庙\n曾经是古代世界最神圣的地方之一,是德尔斐神谕的故乡,也是所有希腊人的圣地。\n尽管这座寺庙现已成为废墟,但其独特的神秘色彩依然存在,它拥有近 3,000 年的历史,位于帕纳苏斯山的高处。\n\n十. 阿布辛贝,埃及\n一座古埃及神庙,由法老拉美西斯二世建造,旨在荣耀法老拉美西斯二世,成为尼罗河上神一般的永恒哨兵。\n它在沙子下消失了两千多年,被挖掘出来,然后在建造阿斯旺大坝时,一块一块地移动。\n\n\n\n十一. 科特迪瓦亚穆苏克罗和平圣母大教堂\n一座建于 20 世纪 80 年代的大教堂,令人难以置信。它的灵感来自罗马圣彼得大教堂,但并非直接模仿。据一些人说,它是世界上最大的教堂。\n\n十二. 帕拉蒂纳无伴奏合唱团,巴勒莫,西西里岛\n许多建筑都被认为是独一无二的——这座建筑确实如此。前所未有的拜占庭式、诺曼式和法蒂玛式建筑矩阵;三种宗教和三种风格的结合。穆卡纳斯、半圆顶、圣像、圆形和尖形拱门……独一无二。\n\n\n\n十三. 贵州梵净山寺庙,中国\n这两座佛教寺庙坐落在武陵山脉深处的岩石上,其历史可以追溯到几个世纪前,看起来几乎是不可能的。\n但它们是真实存在的 — 它们的瓦片由于极端的风力而采用了铁质制作!\n\n十四. 印度泰米尔纳德邦米纳克希神庙\n这座庞大的建筑群有着悠久的历史,可以追溯到 1,000 多年前。它是德拉威建筑的一个令人惊叹的典范,拥有 14 座门楼(仪式性入口塔楼),其中一些具有纪念意义,覆盖着精美的彩色雕塑。', 'bodyHTML': '

个人的信息周刊,每月记录我看到的有价值的信息,主要针对生物学和互联网科技领域,内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。

\n

工具

\n
    \n
  1. 通过人工智能将表情符号变成令人惊叹的艺术品
  2. \n
\n

\n

GitHub 上的一个开源项目,包括了完整的前端和后端代码,支持本地和云端部署,可用于商业用途。

\n
    \n
  1. pdf2htmlEX
  2. \n
\n

\n

\n

一个 PDF 转 HTML 程序,生成的结果和原始 PDF 几乎一模一样。其背后是利用的 Chrome Headless,让 Chrome 渲染 PDF,再导出成 HTML,甚至图片都转成了 base64 字符,所以一个网页就可以包含完整的文本、字体和图片等内容。

\n
    \n
  1. Quartz
  2. \n
\n

Quartz 是一套可帮助您免费将数字花园和笔记发布为网站的工具。Quartz v4 进行了彻底重写,重点关注最终用户的可扩展性和易用性。该工具可直接把 obsidian 笔记部署到线上,可以认为是 Obsidian Publish 功能的替代品,但是是免费的。不仅是 Obsidian 笔记,任何 markdown 双链笔记都可以部署。

\n
    \n
  1. gkd
  2. \n
\n

李跳跳被禁用后的一个替代品,基于高级选择器 + 订阅规则 + 快照审查,它可以实现点击跳过任意开屏广告/点击关闭应用内部任意弹窗广告, 如关闭百度贴吧帖子广告卡片/知乎回答底部推荐广告卡片。

\n
    \n
  1. Blossom
  2. \n
\n

Blossom 是一个支持私有部署的云端存储双链笔记软件,你可以将你所有的笔记,图片,个人计划安排保存在自己的服务器中,并在任意设备之间实时同步,且基于MIT协议完全开源。UI 非常漂亮的一款云端双链笔记。
\n

\n
    \n
  1. MDX Editor - 跨平台微信排版Markdown编辑器
  2. \n
\n

mdx 是 markdown + jsx 的结合,即可以支持 markdown 语法也可以写自定义组件。

\n

支持一键复制到微信公众号、自定义样式组件,样式、生成二维码、代码 diff 高亮、生成文章,软件还支持本地文件实时保存、文件目录树管理和导出 HTML。
\nmdx-editor

\n

文章

\n
    \n
  1. Cloudflare 发布了 2023 年度回顾
  2. \n
\n

2023 年 Cloudflare Radar #YearInReview 是 Cloudflare 对全年在全球和国家/地区层面观察到的各种流量、连接性和速度指标的互联网趋势和模式的第四次年度回顾。

\n

资源

\n
    \n
  1. 你用 Python 做过的最酷的事情是什么?
  2. \n
\n

reddit 上很火的一个讨论,让人大开眼界。

\n
    \n
  1. Data Hacks
  2. \n
\n

一个关于如何处理数据的网站,其中包含 1000 个快速 R 和 Python 教程。在这个网站上,您将会找到关于数据科学和统计学领域各种主题的 R 编程和 Python 编程指南。

\n
    \n
  1. 哪个是程序员最爱的编程字体?2百万阅读的帖子选出最帅的七种字体
  2. \n
\n

最后根据评论选出几款最受欢迎的供大家参考:Consolas,最多人推荐;JetBrains Mono 更推荐它的魔改版本 Jetbrains Mono Nerd Font;SF Mono,同样也有魔改版本 SFMono Nerd Font Ligaturized。

\n
    \n
  1. 大规模语言模型:从理论到实践
  2. \n
\n

复旦大学张奇教授团队写的一本在线免费的电子书,《大规模语言模型:从理论到实践》,大概有 300 页篇幅,将大模型从理论到实战的每个阶段都描述的较为清楚。

\n
    \n
  1. Python 工匠
  2. \n
\n

它专注于分享 Python 编程中的一些偏「小」的东西,例如变量和注释的使用、编写条件分支的技巧、编写跑的更快扩展性更好的代码,让函数反馈结果的技巧、异常处理的好习惯、装饰器的使用技巧等等。

\n

one-python-craftsman

\n
    \n
  1. Python Cookbook in Chinese》 3rd Edition
  2. \n
\n

\n

图片

\n
    \n
  1. 世界上 14 座最伟大的宗教建筑
  2. \n
\n

来源于推特的信息,对于排名和入选不少网友表示怀疑,但的确很震撼。

\n

一. 日本京都金阁寺

\n

金阁寺(“金阁寺”)曾经是邪恶幕府将军的私人住宅,后来被他的儿子改建为禅宗佛教寺庙。
\n那是600年前的事了。它在 20 世纪 50 年代被一位和尚烧毁,并逐梁重建。
\n

\n

二. 英国达勒姆大教堂

\n

英国最精美的诺曼大教堂,以其巨大的 11 世纪鼓柱和坚固的塔楼仍然占据着达勒姆市的主导地位。
\n现在它和一千年前一样庞大,仍然是卡斯伯特和贝德坟墓的所在地。
\n
\n

\n

三. 哈尔格林姆教堂,雷克雅未克,冰岛

\n

世界上最伟大的现代主义教堂之一,将哥特式原则融入现代混凝土和钢材材料中。
\n一个富有表现力、迷人、近乎神奇的传统与现代结合的象征。
\n

\n

四. 印度北阿坎德邦 Gurdwara Sri Hemkund Sahib

\n

有时,让一座建筑变得如此非凡的不仅仅是建筑,还有它的位置。
\n位于喜马拉雅山 Garhwal 近 5,000 米高的 Gurdwara Sri Hemkund Sahib 也是如此。
\n
\n
\n

\n

五. 匈牙利塞格德犹太教堂

\n

这是一件不拘一格的杰作,由 Lipót Baumhorn 于 1902 年设计,充满了彩色玻璃和锻铁。
\n新艺术风格、新哥特式、新罗马式和新摩尔式建筑融合成一个建筑仙境。
\n
\n
\n

\n

六. 迪尔瓦拉耆那教寺庙,印度拉贾斯坦邦

\n

这座寺庙建于 11 世纪至 16 世纪,历时五百年,也许是索兰基风格建筑的最佳典范。
\n精心雕刻的雪白大理石的聚宝盆。
\n
\n
\n

\n

七. 保加利亚索非亚亚历山大涅夫斯基大教堂

\n

一座新拜占庭式建筑的纪念碑,经过三十年的建造,也许是保加利亚脱离奥斯曼帝国独立的顶峰。
\n外面有金色和绿色的圆顶瀑布;里面有一个阴暗的洞穴,里面有蜡烛和图标。
\n

\n

八. 叙利亚大马士革大清真寺

\n

世界上最伟大的建筑之一。这座拥有 4,000 年历史的礼拜场所,在这座从倭马亚王朝到奥斯曼帝国一次又一次改建的杰作的金色马赛克中,仍能看到腓尼基、罗马和早期基督教的遗迹。
\n
\n
\n
\n

\n

九. 希腊德尔斐阿波罗神庙

\n

曾经是古代世界最神圣的地方之一,是德尔斐神谕的故乡,也是所有希腊人的圣地。
\n尽管这座寺庙现已成为废墟,但其独特的神秘色彩依然存在,它拥有近 3,000 年的历史,位于帕纳苏斯山的高处。
\n

\n

十. 阿布辛贝,埃及

\n

一座古埃及神庙,由法老拉美西斯二世建造,旨在荣耀法老拉美西斯二世,成为尼罗河上神一般的永恒哨兵。
\n它在沙子下消失了两千多年,被挖掘出来,然后在建造阿斯旺大坝时,一块一块地移动。
\n
\n
\n

\n

十一. 科特迪瓦亚穆苏克罗和平圣母大教堂

\n

一座建于 20 世纪 80 年代的大教堂,令人难以置信。它的灵感来自罗马圣彼得大教堂,但并非直接模仿。据一些人说,它是世界上最大的教堂。
\n

\n

十二. 帕拉蒂纳无伴奏合唱团,巴勒莫,西西里岛

\n

许多建筑都被认为是独一无二的——这座建筑确实如此。前所未有的拜占庭式、诺曼式和法蒂玛式建筑矩阵;三种宗教和三种风格的结合。穆卡纳斯、半圆顶、圣像、圆形和尖形拱门……独一无二。
\n
\n
\n

\n

十三. 贵州梵净山寺庙,中国

\n

这两座佛教寺庙坐落在武陵山脉深处的岩石上,其历史可以追溯到几个世纪前,看起来几乎是不可能的。
\n但它们是真实存在的 — 它们的瓦片由于极端的风力而采用了铁质制作!
\n

\n

十四. 印度泰米尔纳德邦米纳克希神庙

\n

这座庞大的建筑群有着悠久的历史,可以追溯到 1,000 多年前。它是德拉威建筑的一个令人惊叹的典范,拥有 14 座门楼(仪式性入口塔楼),其中一些具有纪念意义,覆盖着精美的彩色雕塑。
\n
\n
\n

', 'author': {'login': 'shenweiyan'}, 'category': {'name': 'x.2-月刊'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '公众号许久没有更新了', 'number': 28, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/28', 'createdAt': '2023-12-01T02:36:37Z', 'lastEditedAt': '2023-12-08T05:34:13Z', 'updatedAt': '2023-12-08T05:34:13Z', 'body': '大家可能会发现自从 2023 年下半年以来,**"BioIT 爱好者"** 公众号的更新频率越来越低了。\r\n\r\n这里面除了个人私人时间越来越少以外,还有一个原因就是个人把写文章从语雀转移到了 [GitHub](https://github.com/shenweiyan/) 的 Issues 和 Discussions 上。\r\n\r\n\r\n\r\n虽然在很长一段时间以来,个人一直都在使用 [语雀](https://www.yuque.com/shenweiyan) 来记录个人工作、生活的各种知识,但直到今年的下半年在考虑数据多平台使用+备份+搜索的一些使用场景时才发现语雀无法批量导出的一些弊端,更重要的一个原因是正如在 "[博客与写作的一些思考](https://github.com/shenweiyan/Knowledge-Garden/issues/34)" 里面所提到的 **"博客其实就是写给自己看的"**,**"大部分人写所谓 \'博客\' 到最后都把时间花在装潢 CSS HTML 主题上了"**!几经考虑以后,选择了 [GitHub](https://github.com/shenweiyan/) 的 Issues 和 Discussions,对于其中的优点:\r\n\r\n- 全免费,不需要租用域名和服务器;\r\n- 不需要过多折腾,对不懂技术的人来说非常友好;\r\n- Issues/Discussions 自带评论功能,不需要后期为博客安装评论插件;\r\n- GitHub 有网页版和手机 App,只要有网,我们可以随时随地发布文章,而不仅仅局限于电脑;\r\n- 发布到 GitHub 的内容,在 Google 的搜索结果中有非常高的权重;\r\n- 回归 CommonMark 的编辑,方便各种支持 Markdown 平台间的备份迁移;\r\n- 借助 GitHub REST/GraphQL API 可以很方便实现 Issues/Discussions 的导入导出;\r\n- 借助 GitHub Pages 和 GitHub Actions,可以轻松把 Issues/Discussions 转化成静态博客\r\n\r\n借助一些开源的工具,个人目前大部分文章都已经从语 [语雀](https://www.yuque.com/shenweiyan) 同步到了 [shenweiyan/Knowledge-Garden](https://github.com/shenweiyan/Knowledge-Garden),并后续会继续在 GitHub 进行更新,由于[公众号的各种限制和封闭性](https://www.yuque.com/shenweiyan/articles/qw325a),如精力和时间允许后续会同步至公众号。\r\n\r\n![Knowledge-Garden Repo image](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/github-knowledge-garden.png)\r\n\r\n![Knowledge-Garden Discussions image](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/knowledge-garden-discussions.png)\r\n', 'bodyText': '大家可能会发现自从 2023 年下半年以来,"BioIT 爱好者" 公众号的更新频率越来越低了。\n这里面除了个人私人时间越来越少以外,还有一个原因就是个人把写文章从语雀转移到了 GitHub 的 Issues 和 Discussions 上。\n\n虽然在很长一段时间以来,个人一直都在使用 语雀 来记录个人工作、生活的各种知识,但直到今年的下半年在考虑数据多平台使用+备份+搜索的一些使用场景时才发现语雀无法批量导出的一些弊端,更重要的一个原因是正如在 "博客与写作的一些思考" 里面所提到的 "博客其实就是写给自己看的","大部分人写所谓 \'博客\' 到最后都把时间花在装潢 CSS HTML 主题上了"!几经考虑以后,选择了 GitHub 的 Issues 和 Discussions,对于其中的优点:\n\n全免费,不需要租用域名和服务器;\n不需要过多折腾,对不懂技术的人来说非常友好;\nIssues/Discussions 自带评论功能,不需要后期为博客安装评论插件;\nGitHub 有网页版和手机 App,只要有网,我们可以随时随地发布文章,而不仅仅局限于电脑;\n发布到 GitHub 的内容,在 Google 的搜索结果中有非常高的权重;\n回归 CommonMark 的编辑,方便各种支持 Markdown 平台间的备份迁移;\n借助 GitHub REST/GraphQL API 可以很方便实现 Issues/Discussions 的导入导出;\n借助 GitHub Pages 和 GitHub Actions,可以轻松把 Issues/Discussions 转化成静态博客\n\n借助一些开源的工具,个人目前大部分文章都已经从语 语雀 同步到了 shenweiyan/Knowledge-Garden,并后续会继续在 GitHub 进行更新,由于公众号的各种限制和封闭性,如精力和时间允许后续会同步至公众号。', 'bodyHTML': '

大家可能会发现自从 2023 年下半年以来,"BioIT 爱好者" 公众号的更新频率越来越低了。

\n

这里面除了个人私人时间越来越少以外,还有一个原因就是个人把写文章从语雀转移到了 GitHub 的 Issues 和 Discussions 上。

\n\n

虽然在很长一段时间以来,个人一直都在使用 语雀 来记录个人工作、生活的各种知识,但直到今年的下半年在考虑数据多平台使用+备份+搜索的一些使用场景时才发现语雀无法批量导出的一些弊端,更重要的一个原因是正如在 "博客与写作的一些思考" 里面所提到的 "博客其实就是写给自己看的""大部分人写所谓 \'博客\' 到最后都把时间花在装潢 CSS HTML 主题上了"!几经考虑以后,选择了 GitHub 的 Issues 和 Discussions,对于其中的优点:

\n
    \n
  • 全免费,不需要租用域名和服务器;
  • \n
  • 不需要过多折腾,对不懂技术的人来说非常友好;
  • \n
  • Issues/Discussions 自带评论功能,不需要后期为博客安装评论插件;
  • \n
  • GitHub 有网页版和手机 App,只要有网,我们可以随时随地发布文章,而不仅仅局限于电脑;
  • \n
  • 发布到 GitHub 的内容,在 Google 的搜索结果中有非常高的权重;
  • \n
  • 回归 CommonMark 的编辑,方便各种支持 Markdown 平台间的备份迁移;
  • \n
  • 借助 GitHub REST/GraphQL API 可以很方便实现 Issues/Discussions 的导入导出;
  • \n
  • 借助 GitHub Pages 和 GitHub Actions,可以轻松把 Issues/Discussions 转化成静态博客
  • \n
\n

借助一些开源的工具,个人目前大部分文章都已经从语 语雀 同步到了 shenweiyan/Knowledge-Garden,并后续会继续在 GitHub 进行更新,由于公众号的各种限制和封闭性,如精力和时间允许后续会同步至公众号。

\n

Knowledge-Garden Repo image

\n

Knowledge-Garden Discussions image

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': [{'name': '公众号'}]}, 'comments': {'nodes': []}}, {'title': 'Python3 编译安装 --with-openssl 无效的问题', 'number': 27, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/27', 'createdAt': '2023-12-01T02:32:24Z', 'lastEditedAt': None, 'updatedAt': '2024-01-03T07:57:48Z', 'body': '很多人在使用 Python3 经常会遇到一些 openssl 版本太低从而导致包无法正常使用的问题,尤其是 `urllib3` 这个包。\r\n```python\r\nPython 3.9.18 (main, Sep 7 2023, 14:32:17) \r\n[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux\r\nType "help", "copyright", "credits" or "license" for more information.\r\n>>> import requests\r\nTraceback (most recent call last):\r\n File "", line 1, in \r\n File "/usr/local/software/python-3.9.18/lib/python3.9/site-packages/requests/__init__.py", line 43, in \r\n import urllib3\r\n File "/usr/local/software/python-3.9.18/lib/python3.9/site-packages/urllib3/__init__.py", line 41, in \r\n raise ImportError(\r\nImportError: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the \'ssl\' module is compiled with \'OpenSSL 1.0.2k-fips 26 Jan 2017\'. See: https://github.com/urllib3/urllib3/issues/2168\r\n>>> import ssl\r\n>>> import urllib3\r\nTraceback (most recent call last):\r\n File "", line 1, in \r\n File "/usr/local/software/python-3.9.18/lib/python3.9/site-packages/urllib3/__init__.py", line 41, in \r\n raise ImportError(\r\nImportError: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the \'ssl\' module is compiled with \'OpenSSL 1.0.2k-fips 26 Jan 2017\'. See: https://github.com/urllib3/urllib3/issues/2168\r\n```\r\n\r\n网络上有很多关于这方面的教程,主要解决方案:\r\n\r\n1. 降级 `urllib3` 的版本,例如:`pip install --upgrade urllib3==1.26.15`;\r\n2. 重新安装一个更高版本的 OpenSSL,然后备份并替换系统原来的 openssl,最后重新编译安装 Python。\r\n\r\n个人觉得这两个方法都不够好,尤其是第二个方法 —— \r\n\r\n- 新装了一个更高版本的 OpenSSL,但是又不想替换系统原来的 openssl 以免出现新的问题(或者没有管理员权限);\r\n- 在编译的时候使用 `--with-openssl` 指定了新装的 OpenSSL 路径,编译安装完成后 Python **仍然使用旧版本的 OpenSSL**;\r\n\r\n很不幸的是,个人在 CentOS 7.3 + Python-3.9.18 就遇到了这个问题。\r\n\r\n1. 新装了 OpenSSL 3.0.10 \r\n```\r\nwget https://www.openssl.org/source/openssl-3.0.10.tar.gz --no-check-certificate\r\ntar zvxf openssl-3.0.10.tar.gz\r\ncd openssl-3.0.10\r\n./config --prefix=/usr/local/software/openssl-3.0.10 shared zlib\r\nmake && make install\r\n```\r\n\r\n2. 添加 `~/.bashrc` 环境变量\r\n```\r\nexport PATH=/usr/local/software/openssl-3.0.10/bin:$PATH\r\nexport LD_LIBRARY_PATH=/usr/local/software/openssl-3.0.10/lib64:$LD_LIBRARY_PATH\r\n```\r\n\r\n3. 重新编译安装 Python-3.9.18\r\n```\r\n./configure --prefix=/usr/local/software/python-3.9.18 --with-openssl=/usr/local/software/openssl-3.0.10/\r\nmake && make install\r\n```\r\n\r\n等编译完成后,你会神奇的发现重新编译安装后 Python 3.9.18 **仍然使用旧版本的 OpenSSL (OpenSSL 1.0.2k-fips 26 Jan 2017)**!\r\n\r\n其实,这还是因为 Python 在重新编译的时候没有识别到新编译的 OpenSSL,因此,我们需要把重新编译的命令调整一下:\r\n```\r\n/configure --prefix=/usr/local/software/python-3.9.18 \\\r\n--with-openssl=/usr/local/software/openssl-3.0.10/ \\\r\nLDFLAGS="-L/usr/local/software/openssl-3.0.10/lib64" \\\r\nCPPFLAGS="-I/usr/local/software/openssl-3.0.10/include" \\\r\nPKG_CONFIG_PATH="/usr/local/software/openssl-3.0.10/lib64/pkgconfig"\r\n```\r\n\r\n这样子一来,问题就迎刃而解了,编译安装完后,你会发现 Python 3.9.18 已经成功用用上了 OpenSSL 3.0.10 1 Aug 2023:\r\n```\r\n$ python3 -c "import ssl; print(ssl.OPENSSL_VERSION)"\r\nOpenSSL 3.0.10 1 Aug 2023\r\n```\r\n![OpenSSL 3.0.10 on Python3.9.18](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/Gitbook/2023/python-3.9.18-openssl-3.0.10.png)\r\n\r\n## 参考资料\r\n\r\n1. [Drop support for OpenSSL<1.1.1 - urllib3/urllib3#2168](https://github.com/urllib3/urllib3/issues/2168)\r\n\r\n', 'bodyText': '很多人在使用 Python3 经常会遇到一些 openssl 版本太低从而导致包无法正常使用的问题,尤其是 urllib3 这个包。\nPython 3.9.18 (main, Sep 7 2023, 14:32:17) \n[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux\nType "help", "copyright", "credits" or "license" for more information.\n>>> import requests\nTraceback (most recent call last):\n File "", line 1, in \n File "/usr/local/software/python-3.9.18/lib/python3.9/site-packages/requests/__init__.py", line 43, in \n import urllib3\n File "/usr/local/software/python-3.9.18/lib/python3.9/site-packages/urllib3/__init__.py", line 41, in \n raise ImportError(\nImportError: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the \'ssl\' module is compiled with \'OpenSSL 1.0.2k-fips 26 Jan 2017\'. See: https://github.com/urllib3/urllib3/issues/2168\n>>> import ssl\n>>> import urllib3\nTraceback (most recent call last):\n File "", line 1, in \n File "/usr/local/software/python-3.9.18/lib/python3.9/site-packages/urllib3/__init__.py", line 41, in \n raise ImportError(\nImportError: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the \'ssl\' module is compiled with \'OpenSSL 1.0.2k-fips 26 Jan 2017\'. See: https://github.com/urllib3/urllib3/issues/2168\n网络上有很多关于这方面的教程,主要解决方案:\n\n降级 urllib3 的版本,例如:pip install --upgrade urllib3==1.26.15;\n重新安装一个更高版本的 OpenSSL,然后备份并替换系统原来的 openssl,最后重新编译安装 Python。\n\n个人觉得这两个方法都不够好,尤其是第二个方法 ——\n\n新装了一个更高版本的 OpenSSL,但是又不想替换系统原来的 openssl 以免出现新的问题(或者没有管理员权限);\n在编译的时候使用 --with-openssl 指定了新装的 OpenSSL 路径,编译安装完成后 Python 仍然使用旧版本的 OpenSSL;\n\n很不幸的是,个人在 CentOS 7.3 + Python-3.9.18 就遇到了这个问题。\n\n新装了 OpenSSL 3.0.10\n\nwget https://www.openssl.org/source/openssl-3.0.10.tar.gz --no-check-certificate\ntar zvxf openssl-3.0.10.tar.gz\ncd openssl-3.0.10\n./config --prefix=/usr/local/software/openssl-3.0.10 shared zlib\nmake && make install\n\n\n添加 ~/.bashrc 环境变量\n\nexport PATH=/usr/local/software/openssl-3.0.10/bin:$PATH\nexport LD_LIBRARY_PATH=/usr/local/software/openssl-3.0.10/lib64:$LD_LIBRARY_PATH\n\n\n重新编译安装 Python-3.9.18\n\n./configure --prefix=/usr/local/software/python-3.9.18 --with-openssl=/usr/local/software/openssl-3.0.10/\nmake && make install\n\n等编译完成后,你会神奇的发现重新编译安装后 Python 3.9.18 仍然使用旧版本的 OpenSSL (OpenSSL 1.0.2k-fips 26 Jan 2017)!\n其实,这还是因为 Python 在重新编译的时候没有识别到新编译的 OpenSSL,因此,我们需要把重新编译的命令调整一下:\n/configure --prefix=/usr/local/software/python-3.9.18 \\\n--with-openssl=/usr/local/software/openssl-3.0.10/ \\\nLDFLAGS="-L/usr/local/software/openssl-3.0.10/lib64" \\\nCPPFLAGS="-I/usr/local/software/openssl-3.0.10/include" \\\nPKG_CONFIG_PATH="/usr/local/software/openssl-3.0.10/lib64/pkgconfig"\n\n这样子一来,问题就迎刃而解了,编译安装完后,你会发现 Python 3.9.18 已经成功用用上了 OpenSSL 3.0.10 1 Aug 2023:\n$ python3 -c "import ssl; print(ssl.OPENSSL_VERSION)"\nOpenSSL 3.0.10 1 Aug 2023\n\n\n参考资料\n\nDrop support for OpenSSL<1.1.1 - urllib3/urllib3#2168', 'bodyHTML': '

很多人在使用 Python3 经常会遇到一些 openssl 版本太低从而导致包无法正常使用的问题,尤其是 urllib3 这个包。

\n
Python 3.9.18 (main, Sep  7 2023, 14:32:17) \n[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux\nType "help", "copyright", "credits" or "license" for more information.\n>>> import requests\nTraceback (most recent call last):\n  File "<stdin>", line 1, in <module>\n  File "/usr/local/software/python-3.9.18/lib/python3.9/site-packages/requests/__init__.py", line 43, in <module>\n    import urllib3\n  File "/usr/local/software/python-3.9.18/lib/python3.9/site-packages/urllib3/__init__.py", line 41, in <module>\n    raise ImportError(\nImportError: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the \'ssl\' module is compiled with \'OpenSSL 1.0.2k-fips  26 Jan 2017\'. See: https://github.com/urllib3/urllib3/issues/2168\n>>> import ssl\n>>> import urllib3\nTraceback (most recent call last):\n  File "<stdin>", line 1, in <module>\n  File "/usr/local/software/python-3.9.18/lib/python3.9/site-packages/urllib3/__init__.py", line 41, in <module>\n    raise ImportError(\nImportError: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the \'ssl\' module is compiled with \'OpenSSL 1.0.2k-fips  26 Jan 2017\'. See: https://github.com/urllib3/urllib3/issues/2168
\n

网络上有很多关于这方面的教程,主要解决方案:

\n
    \n
  1. 降级 urllib3 的版本,例如:pip install --upgrade urllib3==1.26.15
  2. \n
  3. 重新安装一个更高版本的 OpenSSL,然后备份并替换系统原来的 openssl,最后重新编译安装 Python。
  4. \n
\n

个人觉得这两个方法都不够好,尤其是第二个方法 ——

\n
    \n
  • 新装了一个更高版本的 OpenSSL,但是又不想替换系统原来的 openssl 以免出现新的问题(或者没有管理员权限);
  • \n
  • 在编译的时候使用 --with-openssl 指定了新装的 OpenSSL 路径,编译安装完成后 Python 仍然使用旧版本的 OpenSSL
  • \n
\n

很不幸的是,个人在 CentOS 7.3 + Python-3.9.18 就遇到了这个问题。

\n
    \n
  1. 新装了 OpenSSL 3.0.10
  2. \n
\n
wget https://www.openssl.org/source/openssl-3.0.10.tar.gz --no-check-certificate\ntar zvxf openssl-3.0.10.tar.gz\ncd openssl-3.0.10\n./config --prefix=/usr/local/software/openssl-3.0.10 shared zlib\nmake && make install\n
\n
    \n
  1. 添加 ~/.bashrc 环境变量
  2. \n
\n
export PATH=/usr/local/software/openssl-3.0.10/bin:$PATH\nexport LD_LIBRARY_PATH=/usr/local/software/openssl-3.0.10/lib64:$LD_LIBRARY_PATH\n
\n
    \n
  1. 重新编译安装 Python-3.9.18
  2. \n
\n
./configure --prefix=/usr/local/software/python-3.9.18 --with-openssl=/usr/local/software/openssl-3.0.10/\nmake && make install\n
\n

等编译完成后,你会神奇的发现重新编译安装后 Python 3.9.18 仍然使用旧版本的 OpenSSL (OpenSSL 1.0.2k-fips 26 Jan 2017)

\n

其实,这还是因为 Python 在重新编译的时候没有识别到新编译的 OpenSSL,因此,我们需要把重新编译的命令调整一下:

\n
/configure --prefix=/usr/local/software/python-3.9.18 \\\n--with-openssl=/usr/local/software/openssl-3.0.10/ \\\nLDFLAGS="-L/usr/local/software/openssl-3.0.10/lib64" \\\nCPPFLAGS="-I/usr/local/software/openssl-3.0.10/include" \\\nPKG_CONFIG_PATH="/usr/local/software/openssl-3.0.10/lib64/pkgconfig"\n
\n

这样子一来,问题就迎刃而解了,编译安装完后,你会发现 Python 3.9.18 已经成功用用上了 OpenSSL 3.0.10 1 Aug 2023:

\n
$ python3 -c "import ssl; print(ssl.OPENSSL_VERSION)"\nOpenSSL 3.0.10 1 Aug 2023\n
\n

OpenSSL 3.0.10 on Python3.9.18

\n

参考资料

\n
    \n
  1. Drop support for OpenSSL<1.1.1 - urllib3/urllib3#2168
  2. \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '1.3.5-Python'}]}, 'comments': {'nodes': []}}, {'title': '富文本编辑器与 md 语法的一些困惑', 'number': 26, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/26', 'createdAt': '2023-12-01T02:29:00Z', 'lastEditedAt': '2023-12-01T05:34:04Z', 'updatedAt': '2023-12-01T05:34:04Z', 'body': '在语雀写文档写得多的,会对原始的 Markdown 越来越不敏感。\r\n\r\n语雀的富文本编辑器虽然支持的依然是 markdown,但也有它自身的一些与传统 markdown 不一样的写法,例如 [高亮块](https://www.yuque.com/yuque/gpvawt/rhhxkx)。这样的编辑器把 markdown 的源码给隐藏了——在用户编辑的时候实时进行渲染,这样对于不熟悉 markdown 的用户也极容易上手。\r\n\r\n\r\n\r\n但带来了一个问题,就是使用 markdown 对文档进行导出的时候,有时候会导致 markdown 格式错乱,尤其是当我们想要把语雀的一些文档导出到其他平台时候,这个问题特别烦人。\r\n\r\n![Markdown 语法异常](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/md-error.png)\r\n\r\n回到 GitHub,重新接触纯 Markdown 格式的写法,才真正感觉到这种模式的好处 —— 方便其他支持 Markdown 语法平台的转移,又可以最大限度解决 Markdown 语法错乱的尴尬。\r\n\r\n但也有不好的地方,就是对于多级有序缩进,插入代码后,有序序列(多级缩进)会被打断。。。。\r\n\r\n## 嵌套列表\r\n\r\n通过增加空格,Github 可以实现在嵌套列表中插入代码块;但是这样的做法在 MkDocs 中是有问题的。关于 MkDocs 的嵌套列表,在 https://github.com/mkdocs/mkdocs/issues/545 有一个讨论。\r\n\r\n参考的一个方法:,即使用 [superfences](https://facelessuser.github.io/pymdown-extensions/extensions/superfences/) 插件,加上基于 Python 特有的 4 的倍数个空格进行缩进,可以比较好解决这个问题。\r\n', 'bodyText': '在语雀写文档写得多的,会对原始的 Markdown 越来越不敏感。\n语雀的富文本编辑器虽然支持的依然是 markdown,但也有它自身的一些与传统 markdown 不一样的写法,例如 高亮块。这样的编辑器把 markdown 的源码给隐藏了——在用户编辑的时候实时进行渲染,这样对于不熟悉 markdown 的用户也极容易上手。\n\n但带来了一个问题,就是使用 markdown 对文档进行导出的时候,有时候会导致 markdown 格式错乱,尤其是当我们想要把语雀的一些文档导出到其他平台时候,这个问题特别烦人。\n\n回到 GitHub,重新接触纯 Markdown 格式的写法,才真正感觉到这种模式的好处 —— 方便其他支持 Markdown 语法平台的转移,又可以最大限度解决 Markdown 语法错乱的尴尬。\n但也有不好的地方,就是对于多级有序缩进,插入代码后,有序序列(多级缩进)会被打断。。。。\n嵌套列表\n通过增加空格,Github 可以实现在嵌套列表中插入代码块;但是这样的做法在 MkDocs 中是有问题的。关于 MkDocs 的嵌套列表,在 mkdocs/mkdocs#545 有一个讨论。\n参考的一个方法:mkdocs/mkdocs#2153,即使用 superfences 插件,加上基于 Python 特有的 4 的倍数个空格进行缩进,可以比较好解决这个问题。', 'bodyHTML': '

在语雀写文档写得多的,会对原始的 Markdown 越来越不敏感。

\n

语雀的富文本编辑器虽然支持的依然是 markdown,但也有它自身的一些与传统 markdown 不一样的写法,例如 高亮块。这样的编辑器把 markdown 的源码给隐藏了——在用户编辑的时候实时进行渲染,这样对于不熟悉 markdown 的用户也极容易上手。

\n\n

但带来了一个问题,就是使用 markdown 对文档进行导出的时候,有时候会导致 markdown 格式错乱,尤其是当我们想要把语雀的一些文档导出到其他平台时候,这个问题特别烦人。

\n

Markdown 语法异常

\n

回到 GitHub,重新接触纯 Markdown 格式的写法,才真正感觉到这种模式的好处 —— 方便其他支持 Markdown 语法平台的转移,又可以最大限度解决 Markdown 语法错乱的尴尬。

\n

但也有不好的地方,就是对于多级有序缩进,插入代码后,有序序列(多级缩进)会被打断。。。。

\n

嵌套列表

\n

通过增加空格,Github 可以实现在嵌套列表中插入代码块;但是这样的做法在 MkDocs 中是有问题的。关于 MkDocs 的嵌套列表,在 mkdocs/mkdocs#545 有一个讨论。

\n

参考的一个方法:mkdocs/mkdocs#2153,即使用 superfences 插件,加上基于 Python 特有的 4 的倍数个空格进行缩进,可以比较好解决这个问题。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '不同版本服务器间 SSH 免密码登录失败', 'number': 25, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/25', 'createdAt': '2023-11-30T05:43:06Z', 'lastEditedAt': '2023-12-01T03:01:45Z', 'updatedAt': '2024-01-03T07:56:12Z', 'body': "今天从服务器 A(CentOS 7.3)配置 SSH 无密码登录服务器 B(CentOS Steam 9),发现执行以下常规操作后无法实现:\r\n```\r\n$ ssh-keygen\r\n$ ssh-copy-id -i ~/.ssh/id_rsa.pub shenweiyan@66.xx.xx.xx # ssh-copy-id user@rhel-9-server-IP\r\n$ ssh shenweiyan@66.xx.xx.xx\r\n```\r\n![ssh-keygen-need-passwd](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/ssh-keygen-passwd.png)\r\n\r\n后来,更换 ecdsa 算法,问题才解决:\r\n```\r\n$ ssh-keygen -t ecdsa\r\n$ ssh-copy-id -i ~/.ssh/id_ecdsa.pub shenweiyan@66.xx.xx.xx\r\n```\r\n![ssh-keygen-ecdsa](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/ssh-keygen-ecdsa.png)\r\n\r\n根本原因就在于 SHA-1 已经在 RHEL9 中弃用了!\r\n\r\n从 RHEL9 的官网文档《[1.0.2. Crypto-policies, RHEL core cryptographic components, and protocols](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html-single/considerations_in_adopting_rhel_9/index#ref_considerations-security-crypto_changes-to-security)(加密策略、RHEL 核心加密组件和协议)》可以看到 SHA-1 已经在 RHEL9 中弃用了!\r\n> In RHEL 9, SHA-1 usage for signatures is restricted in the DEFAULT system-wide cryptographic policy. Except for HMAC, SHA-1 is no longer allowed in TLS, DTLS, SSH, IKEv2, DNSSEC, and Kerberos protocols. Individual applications not controlled by the RHEL system-wide crypto policies are also moving away from using SHA-1 hashes in RHEL 9.\r\n\r\n在 RHEL 9 中,用于签名的 SHA-1 用法在 DEFAULT 系统范围的加密策略中受到限制。除 HMAC 外,TLS、DTLS、**SSH**、IKEv2、DNSSEC 和 Kerberos 协议中不再允许使用 SHA-1。不受 RHEL 系统范围的加密策略控制的单个应用程序在 RHEL 9 中也不再使用 SHA-1 hashes。\r\n\r\n## 跨用户免密码登录\r\n\r\n从服务器 A(CentOS 7.3)的 root 用户已配置 SSH 无密码登录服务器 B(CentOS Steam 9)的 shenweiyan 用户。\r\n\r\n- 在服务器 A(CentOS 7.3)的 root 用户下执行以下命令,在 `/root/.ssh` 目录会得到两个文件:\r\n - 私钥文件:**id_ecdsa**\r\n - 公钥文件:**id_ecdsa.pub**\r\n```\r\nroot@centos-vm-7 11:47:20 ~ \r\n$ ssh-keygen -t ecdsa\r\nGenerating public/private ecdsa key pair.\r\nEnter file in which to save the key (/root/.ssh/id_ecdsa): \r\nEnter passphrase (empty for no passphrase): \r\nEnter same passphrase again: \r\nYour identification has been saved in /root/.ssh/id_ecdsa.\r\nYour public key has been saved in /root/.ssh/id_ecdsa.pub.\r\nThe key fingerprint is:\r\nad:15:01:5c:a9:db:69:64:2b:0c:4c:5f:be:f9:e1:44 root@centos-vm-7\r\nThe key's randomart image is:\r\n+--[ECDSA 256]---+\r\n| ..oo. |\r\n| . . o. |\r\n| o . +. |\r\n| o o.+.E |\r\n| oS=o* |\r\n| +oB o |\r\n| .o + . |\r\n| o |\r\n| |\r\n+-----------------+\r\n```\r\n\r\n- 把服务器 A 下 root 用户的公钥文件拷贝到服务器 B(CentOS Steam 9)的 shenweiyan 用户的 authorized_keys 中;\r\n```\r\nroot@centos-vm-7 11:53:25 ~\r\n$ ssh-copy-id -i ~/.ssh/id_ecdsa.pub shenweiyan@66.xx.xx.xx\r\n```\r\n\r\n- 将公钥拷贝至目标服务器 B 后,在源服务器 A 通过密钥跨用户免密码登录云服务器。\r\n```\r\nroot@centos-vm-7 11:58:47 /root \r\n$ ssh shenweiyan@66.xx.xx.xx # ssh -i id_ecdsa shenweiyan@66.xx.xx.xx\r\n```\r\n\r\n## 参考资料\r\n- [RHEL6 ssh 到 RHEL9 的 no hostkey alg 错误](https://www.yuque.com/shenweiyan/cookbook/rhel-9-no-hostkey-alg),语雀\r\n- [How can I use a legacy ssh-rsa key on CentOS 9 Stream?](https://serverfault.com/questions/1095898/how-can-i-use-a-legacy-ssh-rsa-key-on-centos-9-stream),Server Fault\r\n", 'bodyText': "今天从服务器 A(CentOS 7.3)配置 SSH 无密码登录服务器 B(CentOS Steam 9),发现执行以下常规操作后无法实现:\n$ ssh-keygen\n$ ssh-copy-id -i ~/.ssh/id_rsa.pub shenweiyan@66.xx.xx.xx # ssh-copy-id user@rhel-9-server-IP\n$ ssh shenweiyan@66.xx.xx.xx\n\n\n后来,更换 ecdsa 算法,问题才解决:\n$ ssh-keygen -t ecdsa\n$ ssh-copy-id -i ~/.ssh/id_ecdsa.pub shenweiyan@66.xx.xx.xx\n\n\n根本原因就在于 SHA-1 已经在 RHEL9 中弃用了!\n从 RHEL9 的官网文档《1.0.2. Crypto-policies, RHEL core cryptographic components, and protocols(加密策略、RHEL 核心加密组件和协议)》可以看到 SHA-1 已经在 RHEL9 中弃用了!\n\nIn RHEL 9, SHA-1 usage for signatures is restricted in the DEFAULT system-wide cryptographic policy. Except for HMAC, SHA-1 is no longer allowed in TLS, DTLS, SSH, IKEv2, DNSSEC, and Kerberos protocols. Individual applications not controlled by the RHEL system-wide crypto policies are also moving away from using SHA-1 hashes in RHEL 9.\n\n在 RHEL 9 中,用于签名的 SHA-1 用法在 DEFAULT 系统范围的加密策略中受到限制。除 HMAC 外,TLS、DTLS、SSH、IKEv2、DNSSEC 和 Kerberos 协议中不再允许使用 SHA-1。不受 RHEL 系统范围的加密策略控制的单个应用程序在 RHEL 9 中也不再使用 SHA-1 hashes。\n跨用户免密码登录\n从服务器 A(CentOS 7.3)的 root 用户已配置 SSH 无密码登录服务器 B(CentOS Steam 9)的 shenweiyan 用户。\n\n在服务器 A(CentOS 7.3)的 root 用户下执行以下命令,在 /root/.ssh 目录会得到两个文件:\n\n私钥文件:id_ecdsa\n公钥文件:id_ecdsa.pub\n\n\n\nroot@centos-vm-7 11:47:20 ~ \n$ ssh-keygen -t ecdsa\nGenerating public/private ecdsa key pair.\nEnter file in which to save the key (/root/.ssh/id_ecdsa): \nEnter passphrase (empty for no passphrase): \nEnter same passphrase again: \nYour identification has been saved in /root/.ssh/id_ecdsa.\nYour public key has been saved in /root/.ssh/id_ecdsa.pub.\nThe key fingerprint is:\nad:15:01:5c:a9:db:69:64:2b:0c:4c:5f:be:f9:e1:44 root@centos-vm-7\nThe key's randomart image is:\n+--[ECDSA 256]---+\n| ..oo. |\n| . . o. |\n| o . +. |\n| o o.+.E |\n| oS=o* |\n| +oB o |\n| .o + . |\n| o |\n| |\n+-----------------+\n\n\n把服务器 A 下 root 用户的公钥文件拷贝到服务器 B(CentOS Steam 9)的 shenweiyan 用户的 authorized_keys 中;\n\nroot@centos-vm-7 11:53:25 ~\n$ ssh-copy-id -i ~/.ssh/id_ecdsa.pub shenweiyan@66.xx.xx.xx\n\n\n将公钥拷贝至目标服务器 B 后,在源服务器 A 通过密钥跨用户免密码登录云服务器。\n\nroot@centos-vm-7 11:58:47 /root \n$ ssh shenweiyan@66.xx.xx.xx # ssh -i id_ecdsa shenweiyan@66.xx.xx.xx\n\n参考资料\n\nRHEL6 ssh 到 RHEL9 的 no hostkey alg 错误,语雀\nHow can I use a legacy ssh-rsa key on CentOS 9 Stream?,Server Fault", 'bodyHTML': '

今天从服务器 A(CentOS 7.3)配置 SSH 无密码登录服务器 B(CentOS Steam 9),发现执行以下常规操作后无法实现:

\n
$ ssh-keygen\n$ ssh-copy-id -i ~/.ssh/id_rsa.pub shenweiyan@66.xx.xx.xx  # ssh-copy-id user@rhel-9-server-IP\n$ ssh shenweiyan@66.xx.xx.xx\n
\n

ssh-keygen-need-passwd

\n

后来,更换 ecdsa 算法,问题才解决:

\n
$ ssh-keygen -t ecdsa\n$ ssh-copy-id -i ~/.ssh/id_ecdsa.pub shenweiyan@66.xx.xx.xx\n
\n

ssh-keygen-ecdsa

\n

根本原因就在于 SHA-1 已经在 RHEL9 中弃用了!

\n

从 RHEL9 的官网文档《1.0.2. Crypto-policies, RHEL core cryptographic components, and protocols(加密策略、RHEL 核心加密组件和协议)》可以看到 SHA-1 已经在 RHEL9 中弃用了!

\n
\n

In RHEL 9, SHA-1 usage for signatures is restricted in the DEFAULT system-wide cryptographic policy. Except for HMAC, SHA-1 is no longer allowed in TLS, DTLS, SSH, IKEv2, DNSSEC, and Kerberos protocols. Individual applications not controlled by the RHEL system-wide crypto policies are also moving away from using SHA-1 hashes in RHEL 9.

\n
\n

在 RHEL 9 中,用于签名的 SHA-1 用法在 DEFAULT 系统范围的加密策略中受到限制。除 HMAC 外,TLS、DTLS、SSH、IKEv2、DNSSEC 和 Kerberos 协议中不再允许使用 SHA-1。不受 RHEL 系统范围的加密策略控制的单个应用程序在 RHEL 9 中也不再使用 SHA-1 hashes。

\n

跨用户免密码登录

\n

从服务器 A(CentOS 7.3)的 root 用户已配置 SSH 无密码登录服务器 B(CentOS Steam 9)的 shenweiyan 用户。

\n
    \n
  • 在服务器 A(CentOS 7.3)的 root 用户下执行以下命令,在 /root/.ssh 目录会得到两个文件:\n
      \n
    • 私钥文件:id_ecdsa
    • \n
    • 公钥文件:id_ecdsa.pub
    • \n
    \n
  • \n
\n
root@centos-vm-7 11:47:20 ~ \n$ ssh-keygen -t ecdsa\nGenerating public/private ecdsa key pair.\nEnter file in which to save the key (/root/.ssh/id_ecdsa): \nEnter passphrase (empty for no passphrase): \nEnter same passphrase again: \nYour identification has been saved in /root/.ssh/id_ecdsa.\nYour public key has been saved in /root/.ssh/id_ecdsa.pub.\nThe key fingerprint is:\nad:15:01:5c:a9:db:69:64:2b:0c:4c:5f:be:f9:e1:44 root@centos-vm-7\nThe key\'s randomart image is:\n+--[ECDSA  256]---+\n|       ..oo.     |\n|      . . o.     |\n|     o . +.      |\n|      o o.+.E    |\n|       oS=o*     |\n|        +oB o    |\n|        .o + .   |\n|            o    |\n|                 |\n+-----------------+\n
\n
    \n
  • 把服务器 A 下 root 用户的公钥文件拷贝到服务器 B(CentOS Steam 9)的 shenweiyan 用户的 authorized_keys 中;
  • \n
\n
root@centos-vm-7 11:53:25 ~\n$ ssh-copy-id -i ~/.ssh/id_ecdsa.pub shenweiyan@66.xx.xx.xx\n
\n
    \n
  • 将公钥拷贝至目标服务器 B 后,在源服务器 A 通过密钥跨用户免密码登录云服务器。
  • \n
\n
root@centos-vm-7 11:58:47 /root \n$ ssh shenweiyan@66.xx.xx.xx  # ssh -i id_ecdsa shenweiyan@66.xx.xx.xx\n
\n

参考资料

\n', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '1.3.17-服务器配置使用'}]}, 'comments': {'nodes': []}}, {'title': 'Micro/Mamba 安装与注意事项', 'number': 24, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/24', 'createdAt': '2023-11-27T05:37:10Z', 'lastEditedAt': '2024-03-19T06:59:48Z', 'updatedAt': '2024-03-19T06:59:48Z', 'body': '记录一下 Micromamba/Mamba 安装的步骤和注意事项。\r\n\r\n## Mamba 安装\r\n\r\nMamba 可以使用 Mambaforge 方法和已有 Mini/conda 的方式安装,官方推荐的是前面一种,即使用 Mambaforge 进行全新安装。\r\n\r\n### 全新安装\r\n关于 mamba 的安装,官方推荐 [Fresh install](https://mamba.readthedocs.io/en/latest/mamba-installation.html),即全新安装。\r\n\r\n> We recommend that you start with the [Mambaforge distribution](https://github.com/conda-forge/miniforge#mambaforge). Mambaforge comes with the popular conda-forge channel preconfigured, but you can modify the configuration to use any channel you like. Note that Anaconda channels are generally incompatible with conda-forge, so you should not mix them. \r\n> 我们建议您从 Mambaforge 发行版开始。 Mambaforge 预配置了流行的 conda-forge 通道,但您可以修改配置以使用您喜欢的任何通道。请注意,Anaconda 通道通常与 conda-forge 不兼容,因此您不应混合使用它们。\r\n\r\n其实就是: \r\n1. 先去 [Mambaforge distribution](https://github.com/conda-forge/miniforge#mambaforge) 下载 Mambaforge-Linux-x86_64.sh。 \r\n2. 执行 `sh Mambaforge-Linux-x86_64.sh` 安装命令。\r\n\r\n### 在已有的 conda 中安装\r\n\r\n官方文档中明确说不推荐这种安装 Mamba 的方式,他们强烈建议使用 Mambaforge 方法(见上文)。\r\n\r\n这种方法,要获取 `mamba` ,其实只需将其从 `conda-forge` 通道安装到基础环境中即可;但是需要注意 **Installing mamba into any other environment than base is not supported**,即**不支持将 mamba 安装到 base 之外的任何其他环境中**。\r\n\r\n首先,安装 Miniconda。\r\n\r\n参考 ,下载完 Miniconda3-latest-Linux-x86_64.sh,sh 执行一下就可以安装了。\r\n```\r\nsh Miniconda3-latest-Linux-x86_64.sh\r\n```\r\n然后,安装 mamba。\r\n```\r\n~/miniconda3/bin/conda install -c conda-forge mamba\r\n```\r\n\r\n> For both `mamba` and `conda`, the `base` environment is meant to hold their dependencies. It is strongly discouraged to install anything else in the base envionment. Doing so may break `mamba` and `conda` installation. \r\n> 对于 `mamba` 和 `conda` , `base` 环境旨在保存它们的依赖关系。强烈建议不要在基础环境中安装任何其他东西。这样做可能会破坏 `mamba` 和 `conda` 安装。\r\n\r\n## Micromamba 安装\r\n参考 。\r\n\r\n> `micromamba` is a fully statically-linked, self-contained, executable. This means that the `base` environment is completely empty. The configuration for `micromamba` is slighly different, namely all environments and cache will be created by default under the `MAMBA_ROOT_PREFIX` environment variable. There is also no pre-configured `.condarc`/`.mambarc` shipped with micromamba (they are however still read if present). \r\n> `micromamba` 是一个完全静态链接的、独立的可执行文件。这意味着 `base` 环境完全是空的。`micromamba` 的配置略有不同,即默认情况下将在 `MAMBA_ROOT_PREFIX` 环境变量下创建所有环境和缓存。`micromamba` 也没有预配置的 `.condarc` / `.mambarc`(但是,如果存在,它们仍然会被读取)。\r\n\r\n### 脚本安装\r\n\r\n如果您使用的是 macOS、Linux 或 Windows 上的 Git Bash,则有一种简单的安装方法 `micromamba`。只需在您喜欢的 shell 中执行安装脚本即可。\r\n\r\n对于 Linux、macOS 或 Windows 上的 Git Bash,请使用以下命令安装:\r\n```\r\n"${SHELL}" <(curl -L micro.mamba.pm/install.sh)\r\n```\r\n\r\n### 自动更新\r\n安装后,`micromamba` 可以通过下面的方式更新:\r\n```\r\nmicromamba self-update\r\n```\r\n可以指定显式版本:\r\n```\r\nmicromamba self-update --version 1.4.6\r\n```\r\n### 手动更新\r\n\r\n#### Linux 和 macOS\r\n下载并解压可执行文件(来自官方 `conda-forge` 包)即可。\r\n> 其实,这就等同于我们直接去 下载对应平台的二进制文件,或者 `tar.bz2` 文件,然后解压缩,把 `bin/micromamba` 部分提出来使用。\r\n\r\n确保安装了基本实用程序。我们需要 `curl` 和 `tar` 并支持 `bzip2` 。此外,您还需要一个基于 glibc 的系统,例如 Ubuntu、Fedora 或 Centos(Alpine Linux 本身无法运行)。\r\n\r\n以下 magic URL 始终返回 micromamba 的最新可用版本,并且使用 `tar` 自动提取 `bin/micromamba` 部分。\r\n```\r\n# Linux Intel (x86_64):\r\ncurl -Ls https://micro.mamba.pm/api/micromamba/linux-64/latest | tar -xvj bin/micromamba\r\n# Linux ARM64:\r\ncurl -Ls https://micro.mamba.pm/api/micromamba/linux-aarch64/latest | tar -xvj bin/micromamba\r\n# Linux Power:\r\ncurl -Ls https://micro.mamba.pm/api/micromamba/linux-ppc64le/latest | tar -xvj bin/micromamba\r\n# macOS Intel (x86_64):\r\ncurl -Ls https://micro.mamba.pm/api/micromamba/osx-64/latest | tar -xvj bin/micromamba\r\n# macOS Silicon/M1 (ARM64):\r\ncurl -Ls https://micro.mamba.pm/api/micromamba/osx-arm64/latest | tar -xvj bin/micromamba\r\n```\r\n提取完成后,我们就可以使用 `micromamba` 二进制文件了。\r\n\r\n如果您想在临时用例中快速使用 micromamba,您可以运行:\r\n```\r\nexport MAMBA_ROOT_PREFIX=/some/prefix # optional, defaults to ~/micromamba\r\neval "$(./bin/micromamba shell hook -s posix)"\r\n```\r\n这个 shell hook 会修改您的 shell 变量以包含 micromamba 命令。\r\n\r\n如果您想保留这些更改,可以通过运行 `./micromamba shell init ...` 自动将它们写入 `.bashrc` (或 `.zshrc` )。这还允许您选择自定义 MAMBA_ROOT_ENVIRONMENT,这是包和 repodata 缓存所在的位置。\r\n```\r\n# Linux/bash:\r\n./bin/micromamba shell init -s bash -p ~/micromamba # this writes to your .bashrc file\r\n# sourcing the bashrc file incorporates the changes into the running session.\r\n# better yet, restart your terminal!\r\nsource ~/.bashrc\r\n\r\n# macOS/zsh:\r\n./micromamba shell init -s zsh -p ~/micromamba\r\nsource ~/.zshrc\r\n```\r\n\r\n现在您可以激活基本环境并安装新软件包,或创建其他环境。\r\n```\r\nmicromamba activate # this activates the base environment\r\nmicromamba install python=3.6 jupyter -c conda-forge\r\n# or\r\nmicromamba create -n env_name xtensor -c conda-forge\r\nmicromamba activate env_name\r\n```\r\n\r\n专有的 [conda-forge](https://conda-forge.org/) 设置可以配置为:\r\n```\r\nmicromamba config append channels conda-forge\r\nmicromamba config append channels nodefaults\r\nmicromamba config set channel_priority strict\r\n```\r\n', 'bodyText': '记录一下 Micromamba/Mamba 安装的步骤和注意事项。\nMamba 安装\nMamba 可以使用 Mambaforge 方法和已有 Mini/conda 的方式安装,官方推荐的是前面一种,即使用 Mambaforge 进行全新安装。\n全新安装\n关于 mamba 的安装,官方推荐 Fresh install,即全新安装。\n\nWe recommend that you start with the Mambaforge distribution. Mambaforge comes with the popular conda-forge channel preconfigured, but you can modify the configuration to use any channel you like. Note that Anaconda channels are generally incompatible with conda-forge, so you should not mix them.\n我们建议您从 Mambaforge 发行版开始。 Mambaforge 预配置了流行的 conda-forge 通道,但您可以修改配置以使用您喜欢的任何通道。请注意,Anaconda 通道通常与 conda-forge 不兼容,因此您不应混合使用它们。\n\n其实就是:\n\n先去 Mambaforge distribution 下载 Mambaforge-Linux-x86_64.sh。\n执行 sh Mambaforge-Linux-x86_64.sh 安装命令。\n\n在已有的 conda 中安装\n官方文档中明确说不推荐这种安装 Mamba 的方式,他们强烈建议使用 Mambaforge 方法(见上文)。\n这种方法,要获取 mamba ,其实只需将其从 conda-forge 通道安装到基础环境中即可;但是需要注意 Installing mamba into any other environment than base is not supported,即不支持将 mamba 安装到 base 之外的任何其他环境中。\n首先,安装 Miniconda。\n参考 https://docs.conda.io/en/latest/miniconda.html,下载完 Miniconda3-latest-Linux-x86_64.sh,sh 执行一下就可以安装了。\nsh Miniconda3-latest-Linux-x86_64.sh\n\n然后,安装 mamba。\n~/miniconda3/bin/conda install -c conda-forge mamba\n\n\nFor both mamba and conda, the base environment is meant to hold their dependencies. It is strongly discouraged to install anything else in the base envionment. Doing so may break mamba and conda installation.\n对于 mamba 和 conda , base 环境旨在保存它们的依赖关系。强烈建议不要在基础环境中安装任何其他东西。这样做可能会破坏 mamba 和 conda 安装。\n\nMicromamba 安装\n参考 https://mamba.readthedocs.io/en/latest/micromamba-installation.html。\n\nmicromamba is a fully statically-linked, self-contained, executable. This means that the base environment is completely empty. The configuration for micromamba is slighly different, namely all environments and cache will be created by default under the MAMBA_ROOT_PREFIX environment variable. There is also no pre-configured .condarc/.mambarc shipped with micromamba (they are however still read if present).\nmicromamba 是一个完全静态链接的、独立的可执行文件。这意味着 base 环境完全是空的。micromamba 的配置略有不同,即默认情况下将在 MAMBA_ROOT_PREFIX 环境变量下创建所有环境和缓存。micromamba 也没有预配置的 .condarc / .mambarc(但是,如果存在,它们仍然会被读取)。\n\n脚本安装\n如果您使用的是 macOS、Linux 或 Windows 上的 Git Bash,则有一种简单的安装方法 micromamba。只需在您喜欢的 shell 中执行安装脚本即可。\n对于 Linux、macOS 或 Windows 上的 Git Bash,请使用以下命令安装:\n"${SHELL}" <(curl -L micro.mamba.pm/install.sh)\n\n自动更新\n安装后,micromamba 可以通过下面的方式更新:\nmicromamba self-update\n\n可以指定显式版本:\nmicromamba self-update --version 1.4.6\n\n手动更新\nLinux 和 macOS\n下载并解压可执行文件(来自官方 conda-forge 包)即可。\n\n其实,这就等同于我们直接去 https://github.com/mamba-org/micromamba-releases/releases 下载对应平台的二进制文件,或者 tar.bz2 文件,然后解压缩,把 bin/micromamba 部分提出来使用。\n\n确保安装了基本实用程序。我们需要 curl 和 tar 并支持 bzip2 。此外,您还需要一个基于 glibc 的系统,例如 Ubuntu、Fedora 或 Centos(Alpine Linux 本身无法运行)。\n以下 magic URL 始终返回 micromamba 的最新可用版本,并且使用 tar 自动提取 bin/micromamba 部分。\n# Linux Intel (x86_64):\ncurl -Ls https://micro.mamba.pm/api/micromamba/linux-64/latest | tar -xvj bin/micromamba\n# Linux ARM64:\ncurl -Ls https://micro.mamba.pm/api/micromamba/linux-aarch64/latest | tar -xvj bin/micromamba\n# Linux Power:\ncurl -Ls https://micro.mamba.pm/api/micromamba/linux-ppc64le/latest | tar -xvj bin/micromamba\n# macOS Intel (x86_64):\ncurl -Ls https://micro.mamba.pm/api/micromamba/osx-64/latest | tar -xvj bin/micromamba\n# macOS Silicon/M1 (ARM64):\ncurl -Ls https://micro.mamba.pm/api/micromamba/osx-arm64/latest | tar -xvj bin/micromamba\n\n提取完成后,我们就可以使用 micromamba 二进制文件了。\n如果您想在临时用例中快速使用 micromamba,您可以运行:\nexport MAMBA_ROOT_PREFIX=/some/prefix # optional, defaults to ~/micromamba\neval "$(./bin/micromamba shell hook -s posix)"\n\n这个 shell hook 会修改您的 shell 变量以包含 micromamba 命令。\n如果您想保留这些更改,可以通过运行 ./micromamba shell init ... 自动将它们写入 .bashrc (或 .zshrc )。这还允许您选择自定义 MAMBA_ROOT_ENVIRONMENT,这是包和 repodata 缓存所在的位置。\n# Linux/bash:\n./bin/micromamba shell init -s bash -p ~/micromamba # this writes to your .bashrc file\n# sourcing the bashrc file incorporates the changes into the running session.\n# better yet, restart your terminal!\nsource ~/.bashrc\n\n# macOS/zsh:\n./micromamba shell init -s zsh -p ~/micromamba\nsource ~/.zshrc\n\n现在您可以激活基本环境并安装新软件包,或创建其他环境。\nmicromamba activate # this activates the base environment\nmicromamba install python=3.6 jupyter -c conda-forge\n# or\nmicromamba create -n env_name xtensor -c conda-forge\nmicromamba activate env_name\n\n专有的 conda-forge 设置可以配置为:\nmicromamba config append channels conda-forge\nmicromamba config append channels nodefaults\nmicromamba config set channel_priority strict', 'bodyHTML': '

记录一下 Micromamba/Mamba 安装的步骤和注意事项。

\n

Mamba 安装

\n

Mamba 可以使用 Mambaforge 方法和已有 Mini/conda 的方式安装,官方推荐的是前面一种,即使用 Mambaforge 进行全新安装。

\n

全新安装

\n

关于 mamba 的安装,官方推荐 Fresh install,即全新安装。

\n
\n

We recommend that you start with the Mambaforge distribution. Mambaforge comes with the popular conda-forge channel preconfigured, but you can modify the configuration to use any channel you like. Note that Anaconda channels are generally incompatible with conda-forge, so you should not mix them.
\n我们建议您从 Mambaforge 发行版开始。 Mambaforge 预配置了流行的 conda-forge 通道,但您可以修改配置以使用您喜欢的任何通道。请注意,Anaconda 通道通常与 conda-forge 不兼容,因此您不应混合使用它们。

\n
\n

其实就是:

\n
    \n
  1. 先去 Mambaforge distribution 下载 Mambaforge-Linux-x86_64.sh。
  2. \n
  3. 执行 sh Mambaforge-Linux-x86_64.sh 安装命令。
  4. \n
\n

在已有的 conda 中安装

\n

官方文档中明确说不推荐这种安装 Mamba 的方式,他们强烈建议使用 Mambaforge 方法(见上文)。

\n

这种方法,要获取 mamba ,其实只需将其从 conda-forge 通道安装到基础环境中即可;但是需要注意 Installing mamba into any other environment than base is not supported,即不支持将 mamba 安装到 base 之外的任何其他环境中

\n

首先,安装 Miniconda。

\n

参考 https://docs.conda.io/en/latest/miniconda.html,下载完 Miniconda3-latest-Linux-x86_64.sh,sh 执行一下就可以安装了。

\n
sh Miniconda3-latest-Linux-x86_64.sh\n
\n

然后,安装 mamba。

\n
~/miniconda3/bin/conda install -c conda-forge mamba\n
\n
\n

For both mamba and conda, the base environment is meant to hold their dependencies. It is strongly discouraged to install anything else in the base envionment. Doing so may break mamba and conda installation.
\n对于 mambacondabase 环境旨在保存它们的依赖关系。强烈建议不要在基础环境中安装任何其他东西。这样做可能会破坏 mambaconda 安装。

\n
\n

Micromamba 安装

\n

参考 https://mamba.readthedocs.io/en/latest/micromamba-installation.html

\n
\n

micromamba is a fully statically-linked, self-contained, executable. This means that the base environment is completely empty. The configuration for micromamba is slighly different, namely all environments and cache will be created by default under the MAMBA_ROOT_PREFIX environment variable. There is also no pre-configured .condarc/.mambarc shipped with micromamba (they are however still read if present).
\nmicromamba 是一个完全静态链接的、独立的可执行文件。这意味着 base 环境完全是空的。micromamba 的配置略有不同,即默认情况下将在 MAMBA_ROOT_PREFIX 环境变量下创建所有环境和缓存。micromamba 也没有预配置的 .condarc / .mambarc(但是,如果存在,它们仍然会被读取)。

\n
\n

脚本安装

\n

如果您使用的是 macOS、Linux 或 Windows 上的 Git Bash,则有一种简单的安装方法 micromamba。只需在您喜欢的 shell 中执行安装脚本即可。

\n

对于 Linux、macOS 或 Windows 上的 Git Bash,请使用以下命令安装:

\n
"${SHELL}" <(curl -L micro.mamba.pm/install.sh)\n
\n

自动更新

\n

安装后,micromamba 可以通过下面的方式更新:

\n
micromamba self-update\n
\n

可以指定显式版本:

\n
micromamba self-update --version 1.4.6\n
\n

手动更新

\n

Linux 和 macOS

\n

下载并解压可执行文件(来自官方 conda-forge 包)即可。

\n
\n

其实,这就等同于我们直接去 https://github.com/mamba-org/micromamba-releases/releases 下载对应平台的二进制文件,或者 tar.bz2 文件,然后解压缩,把 bin/micromamba 部分提出来使用。

\n
\n

确保安装了基本实用程序。我们需要 curltar 并支持 bzip2 。此外,您还需要一个基于 glibc 的系统,例如 Ubuntu、Fedora 或 Centos(Alpine Linux 本身无法运行)。

\n

以下 magic URL 始终返回 micromamba 的最新可用版本,并且使用 tar 自动提取 bin/micromamba 部分。

\n
# Linux Intel (x86_64):\ncurl -Ls https://micro.mamba.pm/api/micromamba/linux-64/latest | tar -xvj bin/micromamba\n# Linux ARM64:\ncurl -Ls https://micro.mamba.pm/api/micromamba/linux-aarch64/latest | tar -xvj bin/micromamba\n# Linux Power:\ncurl -Ls https://micro.mamba.pm/api/micromamba/linux-ppc64le/latest | tar -xvj bin/micromamba\n# macOS Intel (x86_64):\ncurl -Ls https://micro.mamba.pm/api/micromamba/osx-64/latest | tar -xvj bin/micromamba\n# macOS Silicon/M1 (ARM64):\ncurl -Ls https://micro.mamba.pm/api/micromamba/osx-arm64/latest | tar -xvj bin/micromamba\n
\n

提取完成后,我们就可以使用 micromamba 二进制文件了。

\n

如果您想在临时用例中快速使用 micromamba,您可以运行:

\n
export MAMBA_ROOT_PREFIX=/some/prefix  # optional, defaults to ~/micromamba\neval "$(./bin/micromamba shell hook -s posix)"\n
\n

这个 shell hook 会修改您的 shell 变量以包含 micromamba 命令。

\n

如果您想保留这些更改,可以通过运行 ./micromamba shell init ... 自动将它们写入 .bashrc (或 .zshrc )。这还允许您选择自定义 MAMBA_ROOT_ENVIRONMENT,这是包和 repodata 缓存所在的位置。

\n
# Linux/bash:\n./bin/micromamba shell init -s bash -p ~/micromamba  # this writes to your .bashrc file\n# sourcing the bashrc file incorporates the changes into the running session.\n# better yet, restart your terminal!\nsource ~/.bashrc\n\n# macOS/zsh:\n./micromamba shell init -s zsh -p ~/micromamba\nsource ~/.zshrc\n
\n

现在您可以激活基本环境并安装新软件包,或创建其他环境。

\n
micromamba activate  # this activates the base environment\nmicromamba install python=3.6 jupyter -c conda-forge\n# or\nmicromamba create -n env_name xtensor -c conda-forge\nmicromamba activate env_name\n
\n

专有的 conda-forge 设置可以配置为:

\n
micromamba config append channels conda-forge\nmicromamba config append channels nodefaults\nmicromamba config set channel_priority strict\n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '1.3.22-虚拟环境'}]}, 'comments': {'nodes': []}}, {'title': '大学计算机没有的一课', 'number': 23, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/23', 'createdAt': '2023-11-23T02:04:09Z', 'lastEditedAt': None, 'updatedAt': '2023-11-23T02:04:10Z', 'body': '今天是2023年1月19日,马上要过年了,在这里先提前给大家拜年了,祝大家新年快乐,阖家幸福安康!\r\n\r\n今天来给大家推荐一个不错的开源项目。\r\n\r\n\r\n\r\n大学里的计算机课程往往只专注于讲授数据结构、操作系统这些知识,对于编程开发中常用的工具则留给学生自行学习。在 MIT 这个课程中,你可以了解和掌握命令行(shell)、文本编辑器(Vim)、版本控制系统(Git)等强大的工具,越早接触越能更加熟练地使用它们,有助于未来的职业生涯。\r\n![missing-semester](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/23019-missing-semester.png)\r\n\r\n**地址:**\r\n**中文:**\r\n', 'bodyText': '今天是2023年1月19日,马上要过年了,在这里先提前给大家拜年了,祝大家新年快乐,阖家幸福安康!\n今天来给大家推荐一个不错的开源项目。\n\n大学里的计算机课程往往只专注于讲授数据结构、操作系统这些知识,对于编程开发中常用的工具则留给学生自行学习。在 MIT 这个课程中,你可以了解和掌握命令行(shell)、文本编辑器(Vim)、版本控制系统(Git)等强大的工具,越早接触越能更加熟练地使用它们,有助于未来的职业生涯。\n\n地址:https://github.com/missing-semester/missing-semester\n中文:https://missing-semester-cn.github.io/', 'bodyHTML': '

今天是2023年1月19日,马上要过年了,在这里先提前给大家拜年了,祝大家新年快乐,阖家幸福安康!

\n

今天来给大家推荐一个不错的开源项目。

\n\n

大学里的计算机课程往往只专注于讲授数据结构、操作系统这些知识,对于编程开发中常用的工具则留给学生自行学习。在 MIT 这个课程中,你可以了解和掌握命令行(shell)、文本编辑器(Vim)、版本控制系统(Git)等强大的工具,越早接触越能更加熟练地使用它们,有助于未来的职业生涯。
\nmissing-semester

\n

地址:https://github.com/missing-semester/missing-semester
\n中文:https://missing-semester-cn.github.io/

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.4-知识'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'Notepad++ 在 GitHub 已经沦为战场了', 'number': 22, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/22', 'createdAt': '2023-11-23T01:59:33Z', 'lastEditedAt': '2024-07-16T05:38:26Z', 'updatedAt': '2024-07-16T05:38:26Z', 'body': 'Notepad++ 这片瓜田的瓜都吃了好几年了,作者却一直还在死性不改 。。。。。\r\n\r\n同样的 Notepad++ 在 GitHub 仓库 [notepad-plus-plus](https://github.com/notepad-plus-plus/notepad-plus-plus) 早已沦为反华辱华的垃圾场,群魔乱舞,简直惨不忍睹!\r\n\r\n\r\n\r\n\'say-no-to-Notepad++\'\r\n\r\n## Add random characters\r\n\r\nTwitter: \r\nV2EX:\r\n\r\n![Twitter Notepad++](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/twitter-notepad%2B%2B.png)\r\n\r\n## Free Uyghur\r\n\r\n不知道大家有没有留意,前两天(2019 年 10 月 29)开源文本编辑器 Notepad++ 发布了最新的 \xa0[7.8.1](https://notepad-plus-plus.org/downloads/v7.8.1/)\xa0 版本。\r\n\r\n然而,软件新版本发布后,在该版本中 Notepad++ 的作者同时附加了一篇名为《[Notepad++ v7.8.1 : Free Uyghur](https://notepad-plus-plus.org/news/v781-free-uyghur-edition/)》抹黑中国的文章,具体的内容请大家自行百度(图片是文章部分截图)。而且这已经不是 Notepad++ 第一次这么干了!\r\n![Notepad++ Free Uyghur](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/notepad%2B%2Bv781.png)\r\n\r\nNotepad++ 的 "Free Uyghur" 出来以后,Notepad++ 所在的 Github 瞬间被广大中国的开发者占领,他们用自己的方式进行了回击。小编也忍不住上去看一下,发现 \xa0GitHub 上面基本上都是骂 Notepad++ 作者的,不过也有少数支持作者。\r\n![notepad-781-github-issue1](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/notepad-781-github-issue1.png)\r\n\r\n![notepad-781-github-issue2](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/notepad-781-github-issue2.png)\r\n\r\n## 起底一下开发者\r\n\r\n后来查了一下,Notepad++ 的作者,原来名字叫做侯今吾(英语:DonHO,),是一个毕业于台湾淡江大学及巴黎第七大学的电脑工程师,作为一个台湾人,也是一个台独积极分子,侯今吾借助 Notepad++ 抹黑中国可谓由来已久。\r\n\r\n![Notepad++ DonHO](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/notepad-donho.png)\r\n\r\n## 我也来说几句\r\n\r\n在这里我想说的是,Notepad++ 作为一款免费开源,深受国外编程爱好者赞扬,也为台湾开源界赢得好评,效率很高的文本编辑器,在早年间也是小编最喜欢常用的软件之一。但对于政见这件事情,小编觉得就像吃一道菜一样,你可以选择吃与不吃,不吃,你可以一笑而过,喜欢的人照常吃,与你无关,但你绝对不能吐一口脏东西上去。\r\n\r\n软件本身是没什么问题的,要说软件和作者之间的关系,那就是爱用不用的关系了。同类软件,我不喜欢你作者,当然就不用了,当然我不用也不会对软件发展有什么影响,不过我想说,这就像是去餐馆吃饭。对于顾客来说,他吃与不吃,不会影响服务员的工资。但对于服务员来说,至少不能让顾客觉得你讨厌。\r\n\r\n最后,有人说要抵制 Notepad++,但对我而言,小编是反对把开源与政治挂钩的,因此小编选择不用 Notepad++ —— 我有选择的权利,既然开源的编辑器那么多(我可以用 [Sublime Text](https://www.sublimetext.com/) (虽然 [Sublime Text](https://www.sublimetext.com/) 是非开源的),可以用 [Visual Studio Code](https://code.visualstudio.com/),可以用 [Github Atom](https://atom.io/),也可以用 [BowPad](https://tools.stefankueng.com/BowPad.html)、[Editra](http://editra.org/),甚至是国人开发的 [Notepad--](https://gitee.com/cxasm/notepad--)),我又何必选择一个带政治倾向自己又不喜欢的编辑器呢!\r\n', 'bodyText': 'Notepad++ 这片瓜田的瓜都吃了好几年了,作者却一直还在死性不改 。。。。。\n同样的 Notepad++ 在 GitHub 仓库 notepad-plus-plus 早已沦为反华辱华的垃圾场,群魔乱舞,简直惨不忍睹!\n\n\nAdd random characters\nTwitter:https://twitter.com/Notepad_plus/status/1618276938342359042\nV2EX:https://www.v2ex.com/t/910777\n\nFree Uyghur\n不知道大家有没有留意,前两天(2019 年 10 月 29)开源文本编辑器 Notepad++ 发布了最新的 \xa07.8.1\xa0 版本。\n然而,软件新版本发布后,在该版本中 Notepad++ 的作者同时附加了一篇名为《Notepad++ v7.8.1 : Free Uyghur》抹黑中国的文章,具体的内容请大家自行百度(图片是文章部分截图)。而且这已经不是 Notepad++ 第一次这么干了!\n\nNotepad++ 的 "Free Uyghur" 出来以后,Notepad++ 所在的 Github 瞬间被广大中国的开发者占领,他们用自己的方式进行了回击。小编也忍不住上去看一下,发现 \xa0GitHub 上面基本上都是骂 Notepad++ 作者的,不过也有少数支持作者。\n\n\n起底一下开发者\n后来查了一下,Notepad++ 的作者,原来名字叫做侯今吾(英语:DonHO,https://github.com/donho),是一个毕业于台湾淡江大学及巴黎第七大学的电脑工程师,作为一个台湾人,也是一个台独积极分子,侯今吾借助 Notepad++ 抹黑中国可谓由来已久。\n\n我也来说几句\n在这里我想说的是,Notepad++ 作为一款免费开源,深受国外编程爱好者赞扬,也为台湾开源界赢得好评,效率很高的文本编辑器,在早年间也是小编最喜欢常用的软件之一。但对于政见这件事情,小编觉得就像吃一道菜一样,你可以选择吃与不吃,不吃,你可以一笑而过,喜欢的人照常吃,与你无关,但你绝对不能吐一口脏东西上去。\n软件本身是没什么问题的,要说软件和作者之间的关系,那就是爱用不用的关系了。同类软件,我不喜欢你作者,当然就不用了,当然我不用也不会对软件发展有什么影响,不过我想说,这就像是去餐馆吃饭。对于顾客来说,他吃与不吃,不会影响服务员的工资。但对于服务员来说,至少不能让顾客觉得你讨厌。\n最后,有人说要抵制 Notepad++,但对我而言,小编是反对把开源与政治挂钩的,因此小编选择不用 Notepad++ —— 我有选择的权利,既然开源的编辑器那么多(我可以用 Sublime Text (虽然 Sublime Text 是非开源的),可以用 Visual Studio Code,可以用 Github Atom,也可以用 BowPad、Editra,甚至是国人开发的 Notepad--),我又何必选择一个带政治倾向自己又不喜欢的编辑器呢!', 'bodyHTML': '

Notepad++ 这片瓜田的瓜都吃了好几年了,作者却一直还在死性不改 。。。。。

\n

同样的 Notepad++ 在 GitHub 仓库 notepad-plus-plus 早已沦为反华辱华的垃圾场,群魔乱舞,简直惨不忍睹!

\n\n

say-no-to-Notepad++

\n

Add random characters

\n

Twitter:https://twitter.com/Notepad_plus/status/1618276938342359042
\nV2EX:https://www.v2ex.com/t/910777

\n

Twitter Notepad++

\n

Free Uyghur

\n

不知道大家有没有留意,前两天(2019 年 10 月 29)开源文本编辑器 Notepad++ 发布了最新的 \xa07.8.1\xa0 版本。

\n

然而,软件新版本发布后,在该版本中 Notepad++ 的作者同时附加了一篇名为《Notepad++ v7.8.1 : Free Uyghur》抹黑中国的文章,具体的内容请大家自行百度(图片是文章部分截图)。而且这已经不是 Notepad++ 第一次这么干了!
\nNotepad++ Free Uyghur

\n

Notepad++ 的 "Free Uyghur" 出来以后,Notepad++ 所在的 Github 瞬间被广大中国的开发者占领,他们用自己的方式进行了回击。小编也忍不住上去看一下,发现 \xa0GitHub 上面基本上都是骂 Notepad++ 作者的,不过也有少数支持作者。
\nnotepad-781-github-issue1

\n

notepad-781-github-issue2

\n

起底一下开发者

\n

后来查了一下,Notepad++ 的作者,原来名字叫做侯今吾(英语:DonHO,https://github.com/donho),是一个毕业于台湾淡江大学及巴黎第七大学的电脑工程师,作为一个台湾人,也是一个台独积极分子,侯今吾借助 Notepad++ 抹黑中国可谓由来已久。

\n

Notepad++ DonHO

\n

我也来说几句

\n

在这里我想说的是,Notepad++ 作为一款免费开源,深受国外编程爱好者赞扬,也为台湾开源界赢得好评,效率很高的文本编辑器,在早年间也是小编最喜欢常用的软件之一。但对于政见这件事情,小编觉得就像吃一道菜一样,你可以选择吃与不吃,不吃,你可以一笑而过,喜欢的人照常吃,与你无关,但你绝对不能吐一口脏东西上去。

\n

软件本身是没什么问题的,要说软件和作者之间的关系,那就是爱用不用的关系了。同类软件,我不喜欢你作者,当然就不用了,当然我不用也不会对软件发展有什么影响,不过我想说,这就像是去餐馆吃饭。对于顾客来说,他吃与不吃,不会影响服务员的工资。但对于服务员来说,至少不能让顾客觉得你讨厌。

\n

最后,有人说要抵制 Notepad++,但对我而言,小编是反对把开源与政治挂钩的,因此小编选择不用 Notepad++ —— 我有选择的权利,既然开源的编辑器那么多(我可以用 Sublime Text (虽然 Sublime Text 是非开源的),可以用 Visual Studio Code,可以用 Github Atom,也可以用 BowPadEditra,甚至是国人开发的 Notepad--),我又何必选择一个带政治倾向自己又不喜欢的编辑器呢!

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '2023 年 Galaxy 社区大会会议报告', 'number': 21, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/21', 'createdAt': '2023-11-23T01:47:28Z', 'lastEditedAt': '2023-12-01T05:36:10Z', 'updatedAt': '2024-01-04T05:45:31Z', 'body': '> 作者:Natalie Whitaker \r\n> 编译:[沈维燕](https://weiyan.cc) \r\n> 时间:2023-08-14 \r\n> 原文:[2023 Galaxy Community Conference Meeting Report](https://galaxyproject.org/blog/2023-08-14-gc-c2023-meeting-report/) \r\n\r\n\r\n\t\t\r\n## GCC 2023 会议纪要\r\n\r\n### 概述\r\n2023 年 Galaxy 社区会议(GCC2023)于7月10日至16日在澳大利亚昆士兰州布里斯班昆士兰科技大学举行。GCC 是 Galaxy 社区的年度会议,这是一个旨在在科学和技术层面展示过去一年内在 Galaxy 研究领域做出的令人惊叹的新工作,同时为与会者提供发现合作机会、加强联系、并开辟新的研究方向的大会。 GCC2023 由 Galaxy Australia 和 Australian BioCommons 主办,为期四天,包括了演讲、研讨会/培训、海报和演示等活动,还有三位主题演讲嘉宾和三天的协作节 (CoFest)。除了会议内容,整个 Galaxy 社区会议周还会举办网络交流和社交活动。总体而言,GCC2023 包括了 12.8 小时的长短演讲、37.5 小时的培训、3.3 小时的海报展示和演示,以及 10.6 小时的社交活动和交流。\r\n![GCC2023 Meeting Report Image1](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image1.png)\r\n\r\nGCC2023 共有 91 名现场参会者和 40 名虚拟参会者。来自 21 个不同国家的与会者出席了本次会议:澳大利亚、比利时、巴西、加拿大、捷克、丹麦、法国、德国、印度、爱尔兰、马耳他、摩洛哥、荷兰、新西兰、挪威、新加坡、韩国、斯里兰卡、瑞士、英国和美国(图1)。在总参会人数中,22.4% 是研究助理或技术人员,17.6% 是高级科学家或首席调查员,9.6% 是研究生,7.2% 是博士后,2.4% 是本科生,40% 是其他身份。\r\n\r\n
\r\n GCC2023 Meeting Report Image2\r\n Figure 1. Map of GCC2023 attendees’ countries of origin.\r\n
\r\n\r\n\r\n## 奖学金获得者\r\nGCC2023 非常感谢能够利用一位匿名捐赠者的资金提供现场和虚拟参会的奖学金。作为奖学金的一部分,受奖者被要求通过演讲、海报或二者兼有的方式参与会议。\r\n\r\n今年,一个现场奖学金授予了英国开放大学的一年级博士生 Marisa Loach(Twitter: @Marisa_Loach)。Marisa 进行了一次题为 “为什么使用 Galaxy?用户友好的生物信息学选项的初步结果” 的演讲并展示了一份海报。\r\n![GCC2023 Meeting Report Image3](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image3.png)\r\n\r\nGCC2023共颁发了六个虚拟奖学金。以下列出了每位受奖者及其角色、机构和对会议的贡献。\r\n\r\n### Coline Royaux\r\nTwitter: @ColineRoyaux\r\n\r\n研究生 (Graduate student)\r\n\r\n巴黎索邦大学,法国自然历史博物馆,法国 (Sorbonne University, French Natural History Museum, France)\r\n\r\n演讲标题 “Galaxy-E:基于生态学的 Galaxy 倡议,2022-2023 年更新!” \r\n\r\n### Vajiha Hussain\r\n高年级本科生 (Senior undergraduate student)\r\n\r\n印度维尼昂大学 (Vignan University, India)\r\n\r\n海报标题 “利用 RNASeq 分析识别棕榈蓟马中潜在的 GBNV 生物标志物”\r\n\r\n### Sudeepti Kulshrestha\r\n研究生 (Graduate student)\r\n\r\n印度阿米蒂大学 (Amity University, India)\r\n\r\n海报标题为“使用基于网络的方法探索 Vaginal Microbiome 和先兆子痫的关联”\r\n\r\n### Jonas Bucher\r\n研究生 (Graduate student)\r\n\r\n瑞士苏黎世联邦理工学院,苏黎世大学,瑞士 (Swiss Federal Institute of Technology in Zurich (ETH Zurich), University of Zurich, Switzerland)\r\n\r\n海报标题 “Methylator - DNA cytosine methylation pipeline”\r\n\r\n\r\n### Katarzyna Kamieniecka\r\nTwitter: @katemurat\r\n\r\n研究生 (Graduate student)\r\n\r\n英国布拉德福德大学 (University of Bradford, United Kingdom)\r\n\r\n海报标题 "Galaxy 中的 FAIR 数据管理"\r\n\r\n#### Taoufik Bensellak\r\n研究生 (Graduate student)\r\n\r\n英国利物浦大学 (University of Liverpool, United Kingdom)\r\n\r\n海报标题 “用于微阵列数据分析的 Galaxy 实例和工具”\r\n\r\n## 主讲嘉宾\r\nGCC2023 邀请了三位主题演讲嘉宾,分别就野生动物保护、结构生物学和生物安全等领域分享了他们的思考和研究成果。演讲者展示了他们团队如何通过使用 Galaxy 平台,以更易获取和可复现的方式完成工作。\r\n\r\n三位主题发言人分别发表了内容丰富的演讲,讨论了各自前瞻性研究领域的进展,重点关注开放存取端到端生物信息学 (open-access end-to-end bioinformatics)。Galaxy 在每位主题发言人的最新研究进展中都发挥了重要作用,Galaxy 开发人员和 Galaxy 社区能够亲眼目睹 Galaxy 对科学界的影响。此外,每位主题发言人都为 Galaxy 的未来提供了灵感,并有时间与平台发展轨迹背后的开发人员直接交流。\r\n\r\n### Carolyn Hogg, PhD (University of Sydney,悉尼大学)\r\n来自悉尼大学的 Carolyn Hogg 博士作为第一位主讲人拉开了 GCC2023 的序幕。霍格博士在 "拯救塔斯马尼亚袋獾计划 (Save the Tasmanian Devil Program)" 进行的研究中发挥了重要作用,此外还重点研究了其他澳大利亚物种,如橙腹鹦鹉、考拉、兔耳袋狸和袋鼠。她在 GCC2023 上的演讲题为 “走向无限和超越:结合基因组学和云技术来拯救我们的物种”,强调了自然资源保护主义者和基因组科学家之间合作研究的必要性。她的愿景是通过改变科学、管理和政策的整合方式,为澳大利亚创造保护遗产,而 Galaxy 的使用增强了她的这一愿景。通过使用像 Galaxy 这样的开源平台,Hogg 博士能够产生可重复的基因组科学,以帮助澳大利亚的物种保护和管理实践。\r\n![GCC2023 Meeting Report Image4](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image4.png)\r\n\r\n### Kate Michie, PhD (University of New South Wales,新南威尔士大学)\r\n来自新南威尔士大学的 Kate Michie 博士作为 GCC2023 的第二位主讲人发表了题为 “Alphafold2 和深度学习时代:结构生物学的最新进展” 的演讲。 Michie 博士在蛋白质结构生物学方面拥有二十多年的经验,并广泛使用 Alphafold2,并与众多研究人员密切合作,教他们如何使用这一强大的工具来推进他们的研究。在她的主题演讲中,Michie 博士呼吁关注 Galaxy 为结构生物学研究进展做好准备的迫切需要,这些进展肯定会伴随 Alphafold2 的巨大成功。 Michie 博士的演讲对 GCC2023 来说是一个有影响力的补充,因为 Galaxy 致力于保持竞争力并领先于社区的巨大研究需求。\r\n![GCC2023 Meeting Report Image5](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image5.png)\r\n\r\n### Roberto Barrero, PhD (Queensland University of Technology,昆士兰科技大学)\r\nGCC2023 的最后一位主讲人是来自昆士兰科技大学的 Roberto Barrero 博士。巴雷罗博士的演讲题为 “通过更快、更准确地诊断植物病毒和类病毒,改善植物行业获得新遗传学的机会”,重点讨论利用生物信息学解决农业、植物生物安全和人类健康方面的现实问题。最近,Barrero 博士在开发植物诊断工具包方面发挥了重要作用,该工具包可以在一次测试中准确检测一系列病毒和类病毒,并于 2018 年向他和他的团队授予生物安全影响奖。Barrero 博士的研究进展得到了 Galaxy 的支持通过 GA-VirReport 和高通量测序技术。访问开放式端到端生物信息学工作流程对于诊断植物病毒和类病毒至关重要,Galaxy 很高兴能在 GCC2023 上将这一主题置于前沿。\r\n![GCC2023 Meeting Report Image6](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image6.png)\r\n\r\n## 培训课程\r\n![GCC2023 Meeting Report Image7](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image7.png)\r\n培训是 Galaxy 社区的首要任务。让研究人员能够轻松学习使用该平台、如何进行新的分析或探索能够解决研究人员面临的实际需求的功能和工具,对于 Galaxy 的发展和可持续发展发挥了重要作用。本着这种精神,在 GCC2023 的三天里,共举办了 15 场不同的培训课程,供与会者与专家一起学习和实践生物信息学。专家包括主要研究员、Galaxy 开发人员、项目经理和 Galaxy 高级用户。培训课程主题多种多样,为 GCC2023 的所有与会者提供相关且实用的学习机会。从微生物学和人类遗传学到工作流程和工具开发,GCC2023 培训课程提供了扩大与会者特定研究兴趣和遇到新主题的机会。\r\n\r\n每节课将近三个小时,让学员有时间充分沉浸在教材中,与培训师和其他学员交流,并与来自不同背景的人交流经验和方法。\r\n\r\n## Birds of a Feather (BoF)\r\nBirds of a Feather (BoF) 会议是 GCC 期间的非正式聚会,参与者可以讨论感兴趣的话题。 BoF 每天在会议结束时举行,各小组分成焦点小组,与专家和其他与会者进行交流和讨论。\r\n\r\nGCC2023 期间,与会者有九种不同的机会参加 BoF。今年的 BoF 提出了各种主题,包括备受期待的 Galaxy 高级用户与开发人员对话的机会。此外,BoF 还提供了举办迷你社交活动的机会,例如棋盘游戏、串酒吧和澳大利亚布里斯班徒步之旅!\r\n\r\n## CoFest\r\nGCC2023 主会之后,举办了为期三天的协作节(CoFest)。 CoFest 是 Galaxy 成员的社区聚会,这些成员有兴趣为 Galaxy 的工具集、文档、培训材料、代码库以及扩展 Galaxy 生态系统的其他任何地方做出贡献。 CoFest 的目标是:\r\n\r\n1. 扩大贡献者社区。这次 CoFest 的首要目的是欢迎新的贡献者,帮助您学习资源并结识能够帮助您做出贡献的人。\r\n2. 扩大 Galaxy 生态系统。不仅仅是代码,而是整个生态系统。这包括培训、工具、最佳实践工作流程、文档、测试用例、翻译、基础设施,甚至代码。\r\n\r\nCoFest 的参与者围绕着共同的兴趣,讨论与这些兴趣相关的共同话题。这些群组在 CoFest 开始前、开始时和整个过程中形成,旨在相互之间保持流动和高度互动。今年的 CoFest 分为九大主题:前端、后端、社区、设计、工具、工作流程、培训、测试和辅助项目。由于 CoFest 在整个活动期间都在不断变化和构建,因此主题被进一步细分,重点关注以下主题:交互式工具;升级 Vue3 和上传功能;吸引和保留社区参与活动、管理和领导力;ChatGXY;实施 Galaxy 工具健康审计服务;以及 Simon 的数据俱乐部。\r\n\r\n## 社会事件\r\nGCC2023 希望将 Galaxy 社区的成员联系在一起,因此在整个会议期间举办了不同的社交活动。今年的 GCC2023 社交活动包括为会议拉开序幕的欢迎晚宴、由 Galaxy 社区成员主持的布里斯班徒步游、带有街机游戏的酒馆爬行、桌游之夜、会议晚宴,以及广受好评的 Lone Pine 考拉保护区之行!\r\n\r\n毫无疑问,Lone Pine 考拉保护区是今年社交活动的亮点!一大群 GCC2023 与会者参观了世界上最大的考拉保护区,度过了一个下午,与动物邂逅、野生动物表演,并了解一些澳大利亚最受欢迎的野生动物!\r\n![GCC2023 Meeting Report Image8](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image8.png)\r\n\r\n通过这些有组织的社交活动,Galaxy 社区的成员们在建立职业关系的同时,也建立了友谊。此外,许多社区成员还通过非组织活动,包括游览植物园、参观动物园医院和热带雨林,以及一日游等,彼此建立联系。\r\n\r\n请参阅附录一,了解今年社交活动的更多照片以及遇到的所有令人惊叹的澳大利亚动物!\r\n\r\n## 纪念 Simon Gladman\r\n### Simon 数据俱乐部\r\nSimon Gladman 是 GCC2023 的最初发起者和组织者,如果看到他的伴侣和孩子参加这次会议,他一定会感到非常自豪。Simon 获得了多项荣誉,他作为创新者、榜样、支持者和社区联系者的遗产将继续受到表彰,“星际数据委员会 (Intergalactic Data Commission)” 更名为 “Simon 数据俱乐部 (Simon’s Data Club)”,并在他的组织中获得年度奖项。姓名。\r\n![GCC2023 Meeting Report Image9](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image9.png)\r\n\r\n### Simon Gladman 旅行补助金\r\n已故西蒙·格拉德曼 (Simon Gladman) 对 Galaxy 的贡献将获得以他名字命名的年度奖项。 Galaxy Australia 才华横溢的技术主管和大家的伙伴 Simon 在 GCC2023 上受到了人们的深深怀念,人们对他表示了许多敬意。\r\n\r\nSimon 对 Galaxy 充满热情并与人交流,并且很高兴能够组织在澳大利亚举办的首届国际 Galaxy 社区会议 (GCC)。在 GCC2023 上,我们宣布了首届 Simon Gladman 旅行补助金,以此来庆祝他。每年将向参加 Galaxy 社区活动的澳大利亚公民颁发 5,000 澳元的补助金。\r\n\r\n如果您与 Simon 一样充满热情并希望为 Galaxy 做出贡献,我们鼓励您申请 Simon Gladman 旅行补助金。\r\n\r\n## 感言\r\nGalaxy 执行董事会成员 Michael Schatz 是约翰·霍普金斯大学计算机科学和生物学的彭博杰出教授,他很高兴地看到:\r\n\r\n> *"The keynotes really highlighted how Galaxy enables cutting edge science.”*\r\n> *“主题演讲真正强调了 Galaxy 如何实现尖端科学。”*\r\n\r\n来自 BioCommons、昆士兰网络基础设施基金会 (QCIF)、昆士兰大学、墨尔本生物信息学和 AARNet 的 Galaxy Australia 团队成员发表了从监测工具健康状况到开发最近发布的 Galaxy Australia 基因组实验室等主题。澳大利亚银河服务项目负责人 Gareth Price 博士表示:\r\n\r\n> *“There was a fantastic exchange between our team and international colleagues and wonderful opportunities to engage with the global Galaxy community. GCC was an exhilarating experience, and it was inspiring to be surrounded by like-minded people. The team left full of energy to keep improving Galaxy Australia and strengthen their collaborations with the wider Galaxy community.”*\r\n> *“我们的团队与国际同事之间进行了精彩的交流,并有绝佳的机会与全球 Galaxy 社区互动。 GCC 是一次令人兴奋的经历,周围都是志趣相投的人,这很鼓舞人心。该团队充满活力地继续改进 Galaxy Australia,并加强与更广泛的 Galaxy 社区的合作。”*\r\n\r\n虽然我们是在昆士兰科技大学 (QUT) 的 The Cube 一流设施中举办的,但远程参与的能力是举办真正国际会议的关键因素。尽管 Amrita 大学系统基因组学首席科学家 Prash Suravajhala 博士是 GCC2023 组委会成员,但他无法从印度出发,但他:\r\n\r\n> *“Very excited and happy to be a part of GCC2023 virtually. We witnessed scintillating talks and brainstorming sessions, and the virtual attendance was a treat. This was a cherishing moment for me as I guzzled the talks from early morning India time! It has created a great camaraderie."*\r\n> *“能够以虚拟方式参加 GCC2023 感到非常兴奋和高兴。我们目睹了精彩的演讲和头脑风暴会议,虚拟出席是一种享受。这对我来说是一个珍贵的时刻,因为我沉迷于印度时间清晨的演讲!它创造了伟大的友情。"*\r\n\r\n## Recognition\r\n特别感谢 GCC2023 的赞助商:\r\n\r\n### 白金赞助商\r\nBizData ()\r\n\r\n### 银牌赞助商\r\nLimagrain ()\r\n\r\nGalaxyWorks ()\r\n\r\n### 铜牌赞助商\r\nGIGA Science ()\r\n\r\n\r\n非常感谢所有使 GCC2023 取得成功的个人:\r\n\r\n### 组织和科学委员会\r\nAndrew Lonie\r\n\r\nChristina Hall\r\n\r\nEnis Afgan\r\n\r\nGareth Price\r\n\r\nJenn Vessio\r\n\r\nMargita Jadan\r\n\r\nPrash Suravajhala\r\n\r\nRoberto Barrero Gumiel\r\n\r\nRoss Lazarus\r\n\r\nAssunta DeSanto\r\n\r\nNatalie Whitaker\r\n\r\nSimon Gladman\r\n\r\nClaudia Melogno de Sandoval \r\n\r\n\r\n### 培训协调员\r\nAssunta DeSanto\r\n\r\nIgor Makunin\r\n\r\nMark Crowe\r\n\r\n\r\n### 在线支持\r\nMelissa Burke\r\n\r\nPatrick Capon\r\n\r\n\r\n### 科学计划成员\r\nAndrew Lonie\r\n\r\nAnne Claire Fouilloux\r\n\r\nAnna Syme\r\n\r\nAnshu Bhardwaj\r\n\r\nBérénice Batut\r\n\r\nBryan Raubenolt\r\n\r\nCameron Hyde\r\n\r\nCatherine Bromhead\r\n\r\nClare Sloggett\r\n\r\nCristóbal Gallardo\r\n\r\nDan Blankenberg\r\n\r\nDavor Davidović\r\n\r\nEnis Afgan\r\n\r\nFrederik Coppens\r\n\r\nHans-Rudolf Hotz\r\n\r\nIvan Jakovlić\r\n\r\nJeremy Goecks\r\n\r\nJustin Lee\r\n\r\nMargita Jadan\r\n\r\nMaria Doyle\r\n\r\nMatthias Bernt\r\n\r\nNatalie Kucher\r\n\r\nNicola Soranzo\r\n\r\nNuwan Goonasekera\r\n\r\nPeter van Heusden\r\n\r\nRalf Weber\r\n\r\nRoss Lazarus\r\n\r\nSoyean Kim\r\n\r\nThomas Harrop\r\n\r\nTimothy Griffin\r\n\r\nTyler Collins\r\n\r\nWendi Bacon\r\n\r\nYvan Le Bras\r\n\r\n\r\n### 联合节主办方\r\nCameron Hyde\r\n\r\n## *附录一*\r\n\r\n![GCC2023 Meeting Report Image10](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image10.png)\r\n\r\n![GCC2023 Meeting Report Image11](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image11.png)\r\n\r\n![GCC2023 Meeting Report Image12](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image12.png)\r\n\r\n![GCC2023 Meeting Report Image13](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image13.png)\r\n\r\n![GCC2023 Meeting Report Image14](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image14.png)', 'bodyText': '作者:Natalie Whitaker\n编译:沈维燕\n时间:2023-08-14\n原文:2023 Galaxy Community Conference Meeting Report\n\n\nGCC 2023 会议纪要\n概述\n2023 年 Galaxy 社区会议(GCC2023)于7月10日至16日在澳大利亚昆士兰州布里斯班昆士兰科技大学举行。GCC 是 Galaxy 社区的年度会议,这是一个旨在在科学和技术层面展示过去一年内在 Galaxy 研究领域做出的令人惊叹的新工作,同时为与会者提供发现合作机会、加强联系、并开辟新的研究方向的大会。 GCC2023 由 Galaxy Australia 和 Australian BioCommons 主办,为期四天,包括了演讲、研讨会/培训、海报和演示等活动,还有三位主题演讲嘉宾和三天的协作节 (CoFest)。除了会议内容,整个 Galaxy 社区会议周还会举办网络交流和社交活动。总体而言,GCC2023 包括了 12.8 小时的长短演讲、37.5 小时的培训、3.3 小时的海报展示和演示,以及 10.6 小时的社交活动和交流。\n\nGCC2023 共有 91 名现场参会者和 40 名虚拟参会者。来自 21 个不同国家的与会者出席了本次会议:澳大利亚、比利时、巴西、加拿大、捷克、丹麦、法国、德国、印度、爱尔兰、马耳他、摩洛哥、荷兰、新西兰、挪威、新加坡、韩国、斯里兰卡、瑞士、英国和美国(图1)。在总参会人数中,22.4% 是研究助理或技术人员,17.6% 是高级科学家或首席调查员,9.6% 是研究生,7.2% 是博士后,2.4% 是本科生,40% 是其他身份。\n\n \n Figure 1. Map of GCC2023 attendees’ countries of origin.\n\n奖学金获得者\nGCC2023 非常感谢能够利用一位匿名捐赠者的资金提供现场和虚拟参会的奖学金。作为奖学金的一部分,受奖者被要求通过演讲、海报或二者兼有的方式参与会议。\n今年,一个现场奖学金授予了英国开放大学的一年级博士生 Marisa Loach(Twitter: @Marisa_Loach)。Marisa 进行了一次题为 “为什么使用 Galaxy?用户友好的生物信息学选项的初步结果” 的演讲并展示了一份海报。\n\nGCC2023共颁发了六个虚拟奖学金。以下列出了每位受奖者及其角色、机构和对会议的贡献。\nColine Royaux\nTwitter: @ColineRoyaux\n研究生 (Graduate student)\n巴黎索邦大学,法国自然历史博物馆,法国 (Sorbonne University, French Natural History Museum, France)\n演讲标题 “Galaxy-E:基于生态学的 Galaxy 倡议,2022-2023 年更新!”\nVajiha Hussain\n高年级本科生 (Senior undergraduate student)\n印度维尼昂大学 (Vignan University, India)\n海报标题 “利用 RNASeq 分析识别棕榈蓟马中潜在的 GBNV 生物标志物”\nSudeepti Kulshrestha\n研究生 (Graduate student)\n印度阿米蒂大学 (Amity University, India)\n海报标题为“使用基于网络的方法探索 Vaginal Microbiome 和先兆子痫的关联”\nJonas Bucher\n研究生 (Graduate student)\n瑞士苏黎世联邦理工学院,苏黎世大学,瑞士 (Swiss Federal Institute of Technology in Zurich (ETH Zurich), University of Zurich, Switzerland)\n海报标题 “Methylator - DNA cytosine methylation pipeline”\nKatarzyna Kamieniecka\nTwitter: @katemurat\n研究生 (Graduate student)\n英国布拉德福德大学 (University of Bradford, United Kingdom)\n海报标题 "Galaxy 中的 FAIR 数据管理"\nTaoufik Bensellak\n研究生 (Graduate student)\n英国利物浦大学 (University of Liverpool, United Kingdom)\n海报标题 “用于微阵列数据分析的 Galaxy 实例和工具”\n主讲嘉宾\nGCC2023 邀请了三位主题演讲嘉宾,分别就野生动物保护、结构生物学和生物安全等领域分享了他们的思考和研究成果。演讲者展示了他们团队如何通过使用 Galaxy 平台,以更易获取和可复现的方式完成工作。\n三位主题发言人分别发表了内容丰富的演讲,讨论了各自前瞻性研究领域的进展,重点关注开放存取端到端生物信息学 (open-access end-to-end bioinformatics)。Galaxy 在每位主题发言人的最新研究进展中都发挥了重要作用,Galaxy 开发人员和 Galaxy 社区能够亲眼目睹 Galaxy 对科学界的影响。此外,每位主题发言人都为 Galaxy 的未来提供了灵感,并有时间与平台发展轨迹背后的开发人员直接交流。\nCarolyn Hogg, PhD (University of Sydney,悉尼大学)\n来自悉尼大学的 Carolyn Hogg 博士作为第一位主讲人拉开了 GCC2023 的序幕。霍格博士在 "拯救塔斯马尼亚袋獾计划 (Save the Tasmanian Devil Program)" 进行的研究中发挥了重要作用,此外还重点研究了其他澳大利亚物种,如橙腹鹦鹉、考拉、兔耳袋狸和袋鼠。她在 GCC2023 上的演讲题为 “走向无限和超越:结合基因组学和云技术来拯救我们的物种”,强调了自然资源保护主义者和基因组科学家之间合作研究的必要性。她的愿景是通过改变科学、管理和政策的整合方式,为澳大利亚创造保护遗产,而 Galaxy 的使用增强了她的这一愿景。通过使用像 Galaxy 这样的开源平台,Hogg 博士能够产生可重复的基因组科学,以帮助澳大利亚的物种保护和管理实践。\n\nKate Michie, PhD (University of New South Wales,新南威尔士大学)\n来自新南威尔士大学的 Kate Michie 博士作为 GCC2023 的第二位主讲人发表了题为 “Alphafold2 和深度学习时代:结构生物学的最新进展” 的演讲。 Michie 博士在蛋白质结构生物学方面拥有二十多年的经验,并广泛使用 Alphafold2,并与众多研究人员密切合作,教他们如何使用这一强大的工具来推进他们的研究。在她的主题演讲中,Michie 博士呼吁关注 Galaxy 为结构生物学研究进展做好准备的迫切需要,这些进展肯定会伴随 Alphafold2 的巨大成功。 Michie 博士的演讲对 GCC2023 来说是一个有影响力的补充,因为 Galaxy 致力于保持竞争力并领先于社区的巨大研究需求。\n\nRoberto Barrero, PhD (Queensland University of Technology,昆士兰科技大学)\nGCC2023 的最后一位主讲人是来自昆士兰科技大学的 Roberto Barrero 博士。巴雷罗博士的演讲题为 “通过更快、更准确地诊断植物病毒和类病毒,改善植物行业获得新遗传学的机会”,重点讨论利用生物信息学解决农业、植物生物安全和人类健康方面的现实问题。最近,Barrero 博士在开发植物诊断工具包方面发挥了重要作用,该工具包可以在一次测试中准确检测一系列病毒和类病毒,并于 2018 年向他和他的团队授予生物安全影响奖。Barrero 博士的研究进展得到了 Galaxy 的支持通过 GA-VirReport 和高通量测序技术。访问开放式端到端生物信息学工作流程对于诊断植物病毒和类病毒至关重要,Galaxy 很高兴能在 GCC2023 上将这一主题置于前沿。\n\n培训课程\n\n培训是 Galaxy 社区的首要任务。让研究人员能够轻松学习使用该平台、如何进行新的分析或探索能够解决研究人员面临的实际需求的功能和工具,对于 Galaxy 的发展和可持续发展发挥了重要作用。本着这种精神,在 GCC2023 的三天里,共举办了 15 场不同的培训课程,供与会者与专家一起学习和实践生物信息学。专家包括主要研究员、Galaxy 开发人员、项目经理和 Galaxy 高级用户。培训课程主题多种多样,为 GCC2023 的所有与会者提供相关且实用的学习机会。从微生物学和人类遗传学到工作流程和工具开发,GCC2023 培训课程提供了扩大与会者特定研究兴趣和遇到新主题的机会。\n每节课将近三个小时,让学员有时间充分沉浸在教材中,与培训师和其他学员交流,并与来自不同背景的人交流经验和方法。\nBirds of a Feather (BoF)\nBirds of a Feather (BoF) 会议是 GCC 期间的非正式聚会,参与者可以讨论感兴趣的话题。 BoF 每天在会议结束时举行,各小组分成焦点小组,与专家和其他与会者进行交流和讨论。\nGCC2023 期间,与会者有九种不同的机会参加 BoF。今年的 BoF 提出了各种主题,包括备受期待的 Galaxy 高级用户与开发人员对话的机会。此外,BoF 还提供了举办迷你社交活动的机会,例如棋盘游戏、串酒吧和澳大利亚布里斯班徒步之旅!\nCoFest\nGCC2023 主会之后,举办了为期三天的协作节(CoFest)。 CoFest 是 Galaxy 成员的社区聚会,这些成员有兴趣为 Galaxy 的工具集、文档、培训材料、代码库以及扩展 Galaxy 生态系统的其他任何地方做出贡献。 CoFest 的目标是:\n\n扩大贡献者社区。这次 CoFest 的首要目的是欢迎新的贡献者,帮助您学习资源并结识能够帮助您做出贡献的人。\n扩大 Galaxy 生态系统。不仅仅是代码,而是整个生态系统。这包括培训、工具、最佳实践工作流程、文档、测试用例、翻译、基础设施,甚至代码。\n\nCoFest 的参与者围绕着共同的兴趣,讨论与这些兴趣相关的共同话题。这些群组在 CoFest 开始前、开始时和整个过程中形成,旨在相互之间保持流动和高度互动。今年的 CoFest 分为九大主题:前端、后端、社区、设计、工具、工作流程、培训、测试和辅助项目。由于 CoFest 在整个活动期间都在不断变化和构建,因此主题被进一步细分,重点关注以下主题:交互式工具;升级 Vue3 和上传功能;吸引和保留社区参与活动、管理和领导力;ChatGXY;实施 Galaxy 工具健康审计服务;以及 Simon 的数据俱乐部。\n社会事件\nGCC2023 希望将 Galaxy 社区的成员联系在一起,因此在整个会议期间举办了不同的社交活动。今年的 GCC2023 社交活动包括为会议拉开序幕的欢迎晚宴、由 Galaxy 社区成员主持的布里斯班徒步游、带有街机游戏的酒馆爬行、桌游之夜、会议晚宴,以及广受好评的 Lone Pine 考拉保护区之行!\n毫无疑问,Lone Pine 考拉保护区是今年社交活动的亮点!一大群 GCC2023 与会者参观了世界上最大的考拉保护区,度过了一个下午,与动物邂逅、野生动物表演,并了解一些澳大利亚最受欢迎的野生动物!\n\n通过这些有组织的社交活动,Galaxy 社区的成员们在建立职业关系的同时,也建立了友谊。此外,许多社区成员还通过非组织活动,包括游览植物园、参观动物园医院和热带雨林,以及一日游等,彼此建立联系。\n请参阅附录一,了解今年社交活动的更多照片以及遇到的所有令人惊叹的澳大利亚动物!\n纪念 Simon Gladman\nSimon 数据俱乐部\nSimon Gladman 是 GCC2023 的最初发起者和组织者,如果看到他的伴侣和孩子参加这次会议,他一定会感到非常自豪。Simon 获得了多项荣誉,他作为创新者、榜样、支持者和社区联系者的遗产将继续受到表彰,“星际数据委员会 (Intergalactic Data Commission)” 更名为 “Simon 数据俱乐部 (Simon’s Data Club)”,并在他的组织中获得年度奖项。姓名。\n\nSimon Gladman 旅行补助金\n已故西蒙·格拉德曼 (Simon Gladman) 对 Galaxy 的贡献将获得以他名字命名的年度奖项。 Galaxy Australia 才华横溢的技术主管和大家的伙伴 Simon 在 GCC2023 上受到了人们的深深怀念,人们对他表示了许多敬意。\nSimon 对 Galaxy 充满热情并与人交流,并且很高兴能够组织在澳大利亚举办的首届国际 Galaxy 社区会议 (GCC)。在 GCC2023 上,我们宣布了首届 Simon Gladman 旅行补助金,以此来庆祝他。每年将向参加 Galaxy 社区活动的澳大利亚公民颁发 5,000 澳元的补助金。\n如果您与 Simon 一样充满热情并希望为 Galaxy 做出贡献,我们鼓励您申请 Simon Gladman 旅行补助金。\n感言\nGalaxy 执行董事会成员 Michael Schatz 是约翰·霍普金斯大学计算机科学和生物学的彭博杰出教授,他很高兴地看到:\n\n"The keynotes really highlighted how Galaxy enables cutting edge science.”\n“主题演讲真正强调了 Galaxy 如何实现尖端科学。”\n\n来自 BioCommons、昆士兰网络基础设施基金会 (QCIF)、昆士兰大学、墨尔本生物信息学和 AARNet 的 Galaxy Australia 团队成员发表了从监测工具健康状况到开发最近发布的 Galaxy Australia 基因组实验室等主题。澳大利亚银河服务项目负责人 Gareth Price 博士表示:\n\n“There was a fantastic exchange between our team and international colleagues and wonderful opportunities to engage with the global Galaxy community. GCC was an exhilarating experience, and it was inspiring to be surrounded by like-minded people. The team left full of energy to keep improving Galaxy Australia and strengthen their collaborations with the wider Galaxy community.”\n“我们的团队与国际同事之间进行了精彩的交流,并有绝佳的机会与全球 Galaxy 社区互动。 GCC 是一次令人兴奋的经历,周围都是志趣相投的人,这很鼓舞人心。该团队充满活力地继续改进 Galaxy Australia,并加强与更广泛的 Galaxy 社区的合作。”\n\n虽然我们是在昆士兰科技大学 (QUT) 的 The Cube 一流设施中举办的,但远程参与的能力是举办真正国际会议的关键因素。尽管 Amrita 大学系统基因组学首席科学家 Prash Suravajhala 博士是 GCC2023 组委会成员,但他无法从印度出发,但他:\n\n“Very excited and happy to be a part of GCC2023 virtually. We witnessed scintillating talks and brainstorming sessions, and the virtual attendance was a treat. This was a cherishing moment for me as I guzzled the talks from early morning India time! It has created a great camaraderie."\n“能够以虚拟方式参加 GCC2023 感到非常兴奋和高兴。我们目睹了精彩的演讲和头脑风暴会议,虚拟出席是一种享受。这对我来说是一个珍贵的时刻,因为我沉迷于印度时间清晨的演讲!它创造了伟大的友情。"\n\nRecognition\n特别感谢 GCC2023 的赞助商:\n白金赞助商\nBizData (https://www.bizdata.com.au/)\n银牌赞助商\nLimagrain (https://www.limagrain.com/en)\nGalaxyWorks (https://galaxyworks.io/)\n铜牌赞助商\nGIGA Science (https://academic.oup.com/gigascience?login=false)\n非常感谢所有使 GCC2023 取得成功的个人:\n组织和科学委员会\nAndrew Lonie\nChristina Hall\nEnis Afgan\nGareth Price\nJenn Vessio\nMargita Jadan\nPrash Suravajhala\nRoberto Barrero Gumiel\nRoss Lazarus\nAssunta DeSanto\nNatalie Whitaker\nSimon Gladman\nClaudia Melogno de Sandoval\n培训协调员\nAssunta DeSanto\nIgor Makunin\nMark Crowe\n在线支持\nMelissa Burke\nPatrick Capon\n科学计划成员\nAndrew Lonie\nAnne Claire Fouilloux\nAnna Syme\nAnshu Bhardwaj\nBérénice Batut\nBryan Raubenolt\nCameron Hyde\nCatherine Bromhead\nClare Sloggett\nCristóbal Gallardo\nDan Blankenberg\nDavor Davidović\nEnis Afgan\nFrederik Coppens\nHans-Rudolf Hotz\nIvan Jakovlić\nJeremy Goecks\nJustin Lee\nMargita Jadan\nMaria Doyle\nMatthias Bernt\nNatalie Kucher\nNicola Soranzo\nNuwan Goonasekera\nPeter van Heusden\nRalf Weber\nRoss Lazarus\nSoyean Kim\nThomas Harrop\nTimothy Griffin\nTyler Collins\nWendi Bacon\nYvan Le Bras\n联合节主办方\nCameron Hyde\n附录一', 'bodyHTML': '
\n

作者:Natalie Whitaker
\n编译:沈维燕
\n时间:2023-08-14
\n原文:2023 Galaxy Community Conference Meeting Report

\n
\n\n

GCC 2023 会议纪要

\n

概述

\n

2023 年 Galaxy 社区会议(GCC2023)于7月10日至16日在澳大利亚昆士兰州布里斯班昆士兰科技大学举行。GCC 是 Galaxy 社区的年度会议,这是一个旨在在科学和技术层面展示过去一年内在 Galaxy 研究领域做出的令人惊叹的新工作,同时为与会者提供发现合作机会、加强联系、并开辟新的研究方向的大会。 GCC2023 由 Galaxy Australia 和 Australian BioCommons 主办,为期四天,包括了演讲、研讨会/培训、海报和演示等活动,还有三位主题演讲嘉宾和三天的协作节 (CoFest)。除了会议内容,整个 Galaxy 社区会议周还会举办网络交流和社交活动。总体而言,GCC2023 包括了 12.8 小时的长短演讲、37.5 小时的培训、3.3 小时的海报展示和演示,以及 10.6 小时的社交活动和交流。
\nGCC2023 Meeting Report Image1

\n

GCC2023 共有 91 名现场参会者和 40 名虚拟参会者。来自 21 个不同国家的与会者出席了本次会议:澳大利亚、比利时、巴西、加拿大、捷克、丹麦、法国、德国、印度、爱尔兰、马耳他、摩洛哥、荷兰、新西兰、挪威、新加坡、韩国、斯里兰卡、瑞士、英国和美国(图1)。在总参会人数中,22.4% 是研究助理或技术人员,17.6% 是高级科学家或首席调查员,9.6% 是研究生,7.2% 是博士后,2.4% 是本科生,40% 是其他身份。

\n
\n GCC2023 Meeting Report Image2\n Figure 1. Map of GCC2023 attendees’ countries of origin.\n
\n

奖学金获得者

\n

GCC2023 非常感谢能够利用一位匿名捐赠者的资金提供现场和虚拟参会的奖学金。作为奖学金的一部分,受奖者被要求通过演讲、海报或二者兼有的方式参与会议。

\n

今年,一个现场奖学金授予了英国开放大学的一年级博士生 Marisa Loach(Twitter: @Marisa_Loach)。Marisa 进行了一次题为 “为什么使用 Galaxy?用户友好的生物信息学选项的初步结果” 的演讲并展示了一份海报。
\nGCC2023 Meeting Report Image3

\n

GCC2023共颁发了六个虚拟奖学金。以下列出了每位受奖者及其角色、机构和对会议的贡献。

\n

Coline Royaux

\n

Twitter: @ColineRoyaux

\n

研究生 (Graduate student)

\n

巴黎索邦大学,法国自然历史博物馆,法国 (Sorbonne University, French Natural History Museum, France)

\n

演讲标题 “Galaxy-E:基于生态学的 Galaxy 倡议,2022-2023 年更新!”

\n

Vajiha Hussain

\n

高年级本科生 (Senior undergraduate student)

\n

印度维尼昂大学 (Vignan University, India)

\n

海报标题 “利用 RNASeq 分析识别棕榈蓟马中潜在的 GBNV 生物标志物”

\n

Sudeepti Kulshrestha

\n

研究生 (Graduate student)

\n

印度阿米蒂大学 (Amity University, India)

\n

海报标题为“使用基于网络的方法探索 Vaginal Microbiome 和先兆子痫的关联”

\n

Jonas Bucher

\n

研究生 (Graduate student)

\n

瑞士苏黎世联邦理工学院,苏黎世大学,瑞士 (Swiss Federal Institute of Technology in Zurich (ETH Zurich), University of Zurich, Switzerland)

\n

海报标题 “Methylator - DNA cytosine methylation pipeline”

\n

Katarzyna Kamieniecka

\n

Twitter: @katemurat

\n

研究生 (Graduate student)

\n

英国布拉德福德大学 (University of Bradford, United Kingdom)

\n

海报标题 "Galaxy 中的 FAIR 数据管理"

\n

Taoufik Bensellak

\n

研究生 (Graduate student)

\n

英国利物浦大学 (University of Liverpool, United Kingdom)

\n

海报标题 “用于微阵列数据分析的 Galaxy 实例和工具”

\n

主讲嘉宾

\n

GCC2023 邀请了三位主题演讲嘉宾,分别就野生动物保护、结构生物学和生物安全等领域分享了他们的思考和研究成果。演讲者展示了他们团队如何通过使用 Galaxy 平台,以更易获取和可复现的方式完成工作。

\n

三位主题发言人分别发表了内容丰富的演讲,讨论了各自前瞻性研究领域的进展,重点关注开放存取端到端生物信息学 (open-access end-to-end bioinformatics)。Galaxy 在每位主题发言人的最新研究进展中都发挥了重要作用,Galaxy 开发人员和 Galaxy 社区能够亲眼目睹 Galaxy 对科学界的影响。此外,每位主题发言人都为 Galaxy 的未来提供了灵感,并有时间与平台发展轨迹背后的开发人员直接交流。

\n

Carolyn Hogg, PhD (University of Sydney,悉尼大学)

\n

来自悉尼大学的 Carolyn Hogg 博士作为第一位主讲人拉开了 GCC2023 的序幕。霍格博士在 "拯救塔斯马尼亚袋獾计划 (Save the Tasmanian Devil Program)" 进行的研究中发挥了重要作用,此外还重点研究了其他澳大利亚物种,如橙腹鹦鹉、考拉、兔耳袋狸和袋鼠。她在 GCC2023 上的演讲题为 “走向无限和超越:结合基因组学和云技术来拯救我们的物种”,强调了自然资源保护主义者和基因组科学家之间合作研究的必要性。她的愿景是通过改变科学、管理和政策的整合方式,为澳大利亚创造保护遗产,而 Galaxy 的使用增强了她的这一愿景。通过使用像 Galaxy 这样的开源平台,Hogg 博士能够产生可重复的基因组科学,以帮助澳大利亚的物种保护和管理实践。
\nGCC2023 Meeting Report Image4

\n

Kate Michie, PhD (University of New South Wales,新南威尔士大学)

\n

来自新南威尔士大学的 Kate Michie 博士作为 GCC2023 的第二位主讲人发表了题为 “Alphafold2 和深度学习时代:结构生物学的最新进展” 的演讲。 Michie 博士在蛋白质结构生物学方面拥有二十多年的经验,并广泛使用 Alphafold2,并与众多研究人员密切合作,教他们如何使用这一强大的工具来推进他们的研究。在她的主题演讲中,Michie 博士呼吁关注 Galaxy 为结构生物学研究进展做好准备的迫切需要,这些进展肯定会伴随 Alphafold2 的巨大成功。 Michie 博士的演讲对 GCC2023 来说是一个有影响力的补充,因为 Galaxy 致力于保持竞争力并领先于社区的巨大研究需求。
\nGCC2023 Meeting Report Image5

\n

Roberto Barrero, PhD (Queensland University of Technology,昆士兰科技大学)

\n

GCC2023 的最后一位主讲人是来自昆士兰科技大学的 Roberto Barrero 博士。巴雷罗博士的演讲题为 “通过更快、更准确地诊断植物病毒和类病毒,改善植物行业获得新遗传学的机会”,重点讨论利用生物信息学解决农业、植物生物安全和人类健康方面的现实问题。最近,Barrero 博士在开发植物诊断工具包方面发挥了重要作用,该工具包可以在一次测试中准确检测一系列病毒和类病毒,并于 2018 年向他和他的团队授予生物安全影响奖。Barrero 博士的研究进展得到了 Galaxy 的支持通过 GA-VirReport 和高通量测序技术。访问开放式端到端生物信息学工作流程对于诊断植物病毒和类病毒至关重要,Galaxy 很高兴能在 GCC2023 上将这一主题置于前沿。
\nGCC2023 Meeting Report Image6

\n

培训课程

\n

GCC2023 Meeting Report Image7
\n培训是 Galaxy 社区的首要任务。让研究人员能够轻松学习使用该平台、如何进行新的分析或探索能够解决研究人员面临的实际需求的功能和工具,对于 Galaxy 的发展和可持续发展发挥了重要作用。本着这种精神,在 GCC2023 的三天里,共举办了 15 场不同的培训课程,供与会者与专家一起学习和实践生物信息学。专家包括主要研究员、Galaxy 开发人员、项目经理和 Galaxy 高级用户。培训课程主题多种多样,为 GCC2023 的所有与会者提供相关且实用的学习机会。从微生物学和人类遗传学到工作流程和工具开发,GCC2023 培训课程提供了扩大与会者特定研究兴趣和遇到新主题的机会。

\n

每节课将近三个小时,让学员有时间充分沉浸在教材中,与培训师和其他学员交流,并与来自不同背景的人交流经验和方法。

\n

Birds of a Feather (BoF)

\n

Birds of a Feather (BoF) 会议是 GCC 期间的非正式聚会,参与者可以讨论感兴趣的话题。 BoF 每天在会议结束时举行,各小组分成焦点小组,与专家和其他与会者进行交流和讨论。

\n

GCC2023 期间,与会者有九种不同的机会参加 BoF。今年的 BoF 提出了各种主题,包括备受期待的 Galaxy 高级用户与开发人员对话的机会。此外,BoF 还提供了举办迷你社交活动的机会,例如棋盘游戏、串酒吧和澳大利亚布里斯班徒步之旅!

\n

CoFest

\n

GCC2023 主会之后,举办了为期三天的协作节(CoFest)。 CoFest 是 Galaxy 成员的社区聚会,这些成员有兴趣为 Galaxy 的工具集、文档、培训材料、代码库以及扩展 Galaxy 生态系统的其他任何地方做出贡献。 CoFest 的目标是:

\n
    \n
  1. 扩大贡献者社区。这次 CoFest 的首要目的是欢迎新的贡献者,帮助您学习资源并结识能够帮助您做出贡献的人。
  2. \n
  3. 扩大 Galaxy 生态系统。不仅仅是代码,而是整个生态系统。这包括培训、工具、最佳实践工作流程、文档、测试用例、翻译、基础设施,甚至代码。
  4. \n
\n

CoFest 的参与者围绕着共同的兴趣,讨论与这些兴趣相关的共同话题。这些群组在 CoFest 开始前、开始时和整个过程中形成,旨在相互之间保持流动和高度互动。今年的 CoFest 分为九大主题:前端、后端、社区、设计、工具、工作流程、培训、测试和辅助项目。由于 CoFest 在整个活动期间都在不断变化和构建,因此主题被进一步细分,重点关注以下主题:交互式工具;升级 Vue3 和上传功能;吸引和保留社区参与活动、管理和领导力;ChatGXY;实施 Galaxy 工具健康审计服务;以及 Simon 的数据俱乐部。

\n

社会事件

\n

GCC2023 希望将 Galaxy 社区的成员联系在一起,因此在整个会议期间举办了不同的社交活动。今年的 GCC2023 社交活动包括为会议拉开序幕的欢迎晚宴、由 Galaxy 社区成员主持的布里斯班徒步游、带有街机游戏的酒馆爬行、桌游之夜、会议晚宴,以及广受好评的 Lone Pine 考拉保护区之行!

\n

毫无疑问,Lone Pine 考拉保护区是今年社交活动的亮点!一大群 GCC2023 与会者参观了世界上最大的考拉保护区,度过了一个下午,与动物邂逅、野生动物表演,并了解一些澳大利亚最受欢迎的野生动物!
\nGCC2023 Meeting Report Image8

\n

通过这些有组织的社交活动,Galaxy 社区的成员们在建立职业关系的同时,也建立了友谊。此外,许多社区成员还通过非组织活动,包括游览植物园、参观动物园医院和热带雨林,以及一日游等,彼此建立联系。

\n

请参阅附录一,了解今年社交活动的更多照片以及遇到的所有令人惊叹的澳大利亚动物!

\n

纪念 Simon Gladman

\n

Simon 数据俱乐部

\n

Simon Gladman 是 GCC2023 的最初发起者和组织者,如果看到他的伴侣和孩子参加这次会议,他一定会感到非常自豪。Simon 获得了多项荣誉,他作为创新者、榜样、支持者和社区联系者的遗产将继续受到表彰,“星际数据委员会 (Intergalactic Data Commission)” 更名为 “Simon 数据俱乐部 (Simon’s Data Club)”,并在他的组织中获得年度奖项。姓名。
\nGCC2023 Meeting Report Image9

\n

Simon Gladman 旅行补助金

\n

已故西蒙·格拉德曼 (Simon Gladman) 对 Galaxy 的贡献将获得以他名字命名的年度奖项。 Galaxy Australia 才华横溢的技术主管和大家的伙伴 Simon 在 GCC2023 上受到了人们的深深怀念,人们对他表示了许多敬意。

\n

Simon 对 Galaxy 充满热情并与人交流,并且很高兴能够组织在澳大利亚举办的首届国际 Galaxy 社区会议 (GCC)。在 GCC2023 上,我们宣布了首届 Simon Gladman 旅行补助金,以此来庆祝他。每年将向参加 Galaxy 社区活动的澳大利亚公民颁发 5,000 澳元的补助金。

\n

如果您与 Simon 一样充满热情并希望为 Galaxy 做出贡献,我们鼓励您申请 Simon Gladman 旅行补助金。

\n

感言

\n

Galaxy 执行董事会成员 Michael Schatz 是约翰·霍普金斯大学计算机科学和生物学的彭博杰出教授,他很高兴地看到:

\n
\n

"The keynotes really highlighted how Galaxy enables cutting edge science.”
\n“主题演讲真正强调了 Galaxy 如何实现尖端科学。”

\n
\n

来自 BioCommons、昆士兰网络基础设施基金会 (QCIF)、昆士兰大学、墨尔本生物信息学和 AARNet 的 Galaxy Australia 团队成员发表了从监测工具健康状况到开发最近发布的 Galaxy Australia 基因组实验室等主题。澳大利亚银河服务项目负责人 Gareth Price 博士表示:

\n
\n

“There was a fantastic exchange between our team and international colleagues and wonderful opportunities to engage with the global Galaxy community. GCC was an exhilarating experience, and it was inspiring to be surrounded by like-minded people. The team left full of energy to keep improving Galaxy Australia and strengthen their collaborations with the wider Galaxy community.”
\n“我们的团队与国际同事之间进行了精彩的交流,并有绝佳的机会与全球 Galaxy 社区互动。 GCC 是一次令人兴奋的经历,周围都是志趣相投的人,这很鼓舞人心。该团队充满活力地继续改进 Galaxy Australia,并加强与更广泛的 Galaxy 社区的合作。”

\n
\n

虽然我们是在昆士兰科技大学 (QUT) 的 The Cube 一流设施中举办的,但远程参与的能力是举办真正国际会议的关键因素。尽管 Amrita 大学系统基因组学首席科学家 Prash Suravajhala 博士是 GCC2023 组委会成员,但他无法从印度出发,但他:

\n
\n

“Very excited and happy to be a part of GCC2023 virtually. We witnessed scintillating talks and brainstorming sessions, and the virtual attendance was a treat. This was a cherishing moment for me as I guzzled the talks from early morning India time! It has created a great camaraderie."
\n“能够以虚拟方式参加 GCC2023 感到非常兴奋和高兴。我们目睹了精彩的演讲和头脑风暴会议,虚拟出席是一种享受。这对我来说是一个珍贵的时刻,因为我沉迷于印度时间清晨的演讲!它创造了伟大的友情。"

\n
\n

Recognition

\n

特别感谢 GCC2023 的赞助商:

\n

白金赞助商

\n

BizData (https://www.bizdata.com.au/)

\n

银牌赞助商

\n

Limagrain (https://www.limagrain.com/en)

\n

GalaxyWorks (https://galaxyworks.io/)

\n

铜牌赞助商

\n

GIGA Science (https://academic.oup.com/gigascience?login=false)

\n

非常感谢所有使 GCC2023 取得成功的个人:

\n

组织和科学委员会

\n

Andrew Lonie

\n

Christina Hall

\n

Enis Afgan

\n

Gareth Price

\n

Jenn Vessio

\n

Margita Jadan

\n

Prash Suravajhala

\n

Roberto Barrero Gumiel

\n

Ross Lazarus

\n

Assunta DeSanto

\n

Natalie Whitaker

\n

Simon Gladman

\n

Claudia Melogno de Sandoval

\n

培训协调员

\n

Assunta DeSanto

\n

Igor Makunin

\n

Mark Crowe

\n

在线支持

\n

Melissa Burke

\n

Patrick Capon

\n

科学计划成员

\n

Andrew Lonie

\n

Anne Claire Fouilloux

\n

Anna Syme

\n

Anshu Bhardwaj

\n

Bérénice Batut

\n

Bryan Raubenolt

\n

Cameron Hyde

\n

Catherine Bromhead

\n

Clare Sloggett

\n

Cristóbal Gallardo

\n

Dan Blankenberg

\n

Davor Davidović

\n

Enis Afgan

\n

Frederik Coppens

\n

Hans-Rudolf Hotz

\n

Ivan Jakovlić

\n

Jeremy Goecks

\n

Justin Lee

\n

Margita Jadan

\n

Maria Doyle

\n

Matthias Bernt

\n

Natalie Kucher

\n

Nicola Soranzo

\n

Nuwan Goonasekera

\n

Peter van Heusden

\n

Ralf Weber

\n

Ross Lazarus

\n

Soyean Kim

\n

Thomas Harrop

\n

Timothy Griffin

\n

Tyler Collins

\n

Wendi Bacon

\n

Yvan Le Bras

\n

联合节主办方

\n

Cameron Hyde

\n

附录一

\n

GCC2023 Meeting Report Image10

\n

GCC2023 Meeting Report Image11

\n

GCC2023 Meeting Report Image12

\n

GCC2023 Meeting Report Image13

\n

GCC2023 Meeting Report Image14

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.3-资讯'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '兆碱基中关于 Kb、KB、Bps、bps 的区别', 'number': 20, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/20', 'createdAt': '2023-11-23T01:39:14Z', 'lastEditedAt': '2023-11-23T02:48:23Z', 'updatedAt': '2023-11-23T02:48:23Z', 'body': '生物信息很多文章都提到 DNA 序列的 100 万个碱基数据(兆碱基)大致相当于计算机 1 兆的存储空间。借着这个问题,我们今天来聊一聊计算机存储和数据传输中 Kb、KB、Bps、bps 的一些区别,分析一下所谓的兆碱基到底是使用哪一种标准(单位)怎么计算出来的。\r\n\r\n\r\n\r\n## 计算机存储容量单位\r\n\r\nBit (binary digit):亦称二进制位,指二进制中的一位,是信息的最小单位。位的值只会是 0 或 1。虽然计算机也提供对位的判断和操作,但是计算机指令一般以字节(Byte)为单位。在大多数的计算机系统中,八位是一个字节。一位的值通常以存储电容是否带电来衡量。\r\n\r\nB (Byte):字节。8 个二进制位构成 1 个"字节(Byte)",它是电脑存储空间的基本计量单位。1 字节 (Byte)=8(bit) 位,就是有 8 个二进制数组成。1 个英文字符是 1 个字节,也就是 1B;1 个汉字为 2 个字符,也就是 2B。\r\n\r\nGB (Gigabyte):吉字节,是一种**十进制**的信息计量单位。Gibibyte(giga binary byte 的缩写)则是**二进制**信息计量的一个单位,简称 GiB。吉字节(Gigabyte)常容易和二进制的信息计量单位 Gibibyte 混淆。\r\n\r\n> Gibibyte 与 Gigabyte 常常被混淆,前者的计算方式是二进制,后者的计算方式是十进制。现今的计算上,常把 Gigabyte 以二进制的方式计算,即 $2^{30} = 1,073,741,824$ 。(因为 Windows 对 GB 这个信息计量单位的误用,因此在 Windows 中显示的 "1GB",其实应是指 "1GiB",但 Windows 却显示为 "1GB",而常造成误解。误用会普遍化的一大因素,是因为 Windows 的操作系统占有率高),由于两种换算方法的不同,使容量在计算上相差了 7.3%,所以常有 Windows 系统报告的容量比硬盘标示的容量还要小的情况发生。但在苹果公司的 OS X 操作系统中,对于存储设备的容量计算方式与硬盘厂商一致,均为 1GB = 1,000,000,000 ( $10^{9}$ ) 字节的十进制,避免了计算和使用上的麻烦。\r\n>\r\n> —— 维基百科 - Gibibyte,\r\n\r\nK、M、G 都是 KB、MB、GB 的简称。由于混淆已经普遍化,Gigabyte 往往是指 Gibibyte,所以平时我们说的 1 兆存储就是 1M(MB),1G 存储就是 1GB)。我们的照片一般是 104KB、209KB、1.45MB、2.45MB、3.32MB 等等。\r\n\r\n在说明其他储存单位的换算前,我们来看看两个标准:SI、IEC。\r\n\r\n### 国际单位制(SI)\r\n\r\n国际单位制(简称 SI,来自于法语 Système International d\'Unités),是世界上最普遍采用的标准度量系统。国际单位制以七个基本单位(米(m),千克(kg),秒(s),安培(A),开尔文(K),摩尔(mol),坎德拉(cd))为基础,由此建立起一系列相互换算关系明确的"一致单位"。另有二十个基于十进制的词头,当加在单位名称或符号前的时候,可用于表达该单位的倍数或分数。\r\n\r\n### 国际电工委员会(IEC)\r\n\r\n国际电工委员会(IEC, International Electrotechnical Commission)成立于 1906 年,至今已有 90 多年的历史。它是世界上成立最早的国际性电工标准化机构,负责有关电气工程和电子工程领域中的国际标准化工作。\r\n\r\nIEC 的宗旨是,促进电气、电子工程领域中标准化及有关问题的国际合作,增进国际间的相互了解。为实现这一目的,IEC 出版包括国际标准在内的各种出版物,并希望各成员在本国条件允许的情况下,在本国的标准化工作中使用这些标准。\r\n\r\n目前 IEC 的工作领域已由单纯研究电气设备、电机的名词术语和功率等问题扩展到电子、电力、微电子及其应用、通讯、视听、机器人、信息技术、新型医疗器械和核仪表等电工技术的各个方面。IEC 标准的权威性是世界公认的,截止到 2008 年 12 月底,IEC 已制定了 5425 个国际标准。\r\n\r\n不同标准下储存单位的次方单位 ( $2^{10}=1024$ ):\r\n\r\n![字节的次方单位](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/byte-wiki.png)\r\n\r\n## 比特率单位\r\n\r\n在电信和计算领域,比特率(Bit rate)是指单位时间内传输送或处理的比特的数量。比特率经常在电信领域用作连接速度、传输速度、信息传输速率和数字带宽容量的同义词。\r\n\r\n在数字多媒体领域,比特率是单位时间播放连续的媒体如压缩后的音频或视频的比特数量。在这个意义上讲,它相当于术语数字带宽消耗量,或吞吐量。\r\n\r\n比特率规定使用"比特每秒"(bit/s 或 bps)为单位,经常和国际单位制词头关联在一起:\r\n\r\n- bps(bit/s),即 bit pro second(位每秒);\r\n\r\n- Kbps(Kbit/s),即 Kilobit pro second(千位每秒);\r\n\r\n- Mbps(Mbit/s),即 Milionbit pro second(百万位每秒)。\r\n\r\n其中,bit 即比特,通常用 b(小写)表示,指一位二进制位,Milionbit=1000Kilobit=1000 000bit,所以 1Mbps=1000 000bps;\r\n\r\n### bps 和 Bps\r\n\r\nbps 是通常用来**衡量带宽**的单位,常见于表示数据机及网络通讯的传输速率,指每秒钟传输的二进制位数。例如 GigabitEthernet 端口。\r\n```\r\n5 minute input rate 38410000 bits/sec, 6344 packets/sec\r\n382410000 bits/sec = 382.41Mbps\r\n```\r\n\r\n通常电脑(软件)上显示的上传下载速度(如下面的阿里云 OSSBrowser、Google Chrome 数据下载速度),则是指每秒种传输的字节数(Byte)通常用 B(大写)表示:MB 即百万字节也称兆字节;KB 即千字节;B 即字节。\r\n\r\n- 1B=8b\r\n\r\n- 1MB=1024KB=1024\\*1024B\r\n\r\n- 1Mbps=1000Kbps=1000/8KBps=125KBps\r\n\r\n我们通常说的 1M 带宽即指 1Mbps,因此 1M 的带宽下载的速度一般不会超过 125KB 每秒。2M、3M 带宽的下载速度分别不会超过 250KB、375KB 每秒。\r\n\r\n![download-byte-rate](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/download-byte-rate.png)\r\n\r\n**数据传输速率的衡量单位 K 是十进制含义,但数据存储的 K 是 2 进制含义。**\r\n\r\n1kbit/s 就是 1000bit/s,而 KB 是 1024 个字节,注意 KB(KByte) 和 kbit 的区别,另外,数据传输速率的单位是 bit/s 记作:bps 。\r\n\r\n在实际应用中:\r\n\r\n- 1kbps=1000bps\r\n\r\n- 1Mbps=1000,000bps\r\n\r\n- 1bps=0.000001bps\r\n\r\n1Mbps 与 1m/s 是有区别的,1m/s 指的是 1024KB/s,而 1Mbps 指的是(1000/8)KB/s 也就是 125KB/S。\r\n\r\n记住 K 和 k 是没区别的 \xa0,区别在于 bps 属于位每秒的单位,而 m/s ,KB/s 这两个属于字节每秒的单位,一字节等于 8 位,即 1k=8b。\r\n\r\n## 兆碱基\r\n\r\n所以,在文章开头提到的 DNA 序列的 100 万个碱基数据(兆碱基)大致相当于计算机 1 兆的存储空间。其实也就是这么计算来得:\r\n\r\n一个碱基就是一个英文字母,而一个英文字母是 1 个字节(Byte),所以 100 万个碱基就是 1000,000 Byte。按照 SI 国际单位的十进制标准,正好相当于 1 MB,如果按照 IEC 国际电工委员会的二进制标准,应该为:1000,000 / 1024 /1024 ≈ 0.95 MB,则是大致相当于计算机 1 兆的存储空间。\r\n\r\n## 参考资料\r\n\r\n- [Wiki: Gibibyte](https://zh.wikipedia.org/wiki/Gibibyte),维基百科\r\n- [Wiki:比特率](https://zh.wikipedia.org/wiki/%E6%AF%94%E7%89%B9%E7%8E%87),维基百科\r\n- 沙翁,《[什么是 Mbps、Kbps、bps、kb、mb 及其换算和区别](https://www.cnblogs.com/shaweng/p/3816985.html)》,博客园\r\n- 大任 Dren,《[bit、Byte、bps、Bps、pps、Gbps 的单位详细说明及换算](https://blog.csdn.net/a9254778/article/details/8513086)》,CSDN-专业 IT 技术社区\r\n', 'bodyText': '生物信息很多文章都提到 DNA 序列的 100 万个碱基数据(兆碱基)大致相当于计算机 1 兆的存储空间。借着这个问题,我们今天来聊一聊计算机存储和数据传输中 Kb、KB、Bps、bps 的一些区别,分析一下所谓的兆碱基到底是使用哪一种标准(单位)怎么计算出来的。\n\n计算机存储容量单位\nBit (binary digit):亦称二进制位,指二进制中的一位,是信息的最小单位。位的值只会是 0 或 1。虽然计算机也提供对位的判断和操作,但是计算机指令一般以字节(Byte)为单位。在大多数的计算机系统中,八位是一个字节。一位的值通常以存储电容是否带电来衡量。\nB (Byte):字节。8 个二进制位构成 1 个"字节(Byte)",它是电脑存储空间的基本计量单位。1 字节 (Byte)=8(bit) 位,就是有 8 个二进制数组成。1 个英文字符是 1 个字节,也就是 1B;1 个汉字为 2 个字符,也就是 2B。\nGB (Gigabyte):吉字节,是一种十进制的信息计量单位。Gibibyte(giga binary byte 的缩写)则是二进制信息计量的一个单位,简称 GiB。吉字节(Gigabyte)常容易和二进制的信息计量单位 Gibibyte 混淆。\n\nGibibyte 与 Gigabyte 常常被混淆,前者的计算方式是二进制,后者的计算方式是十进制。现今的计算上,常把 Gigabyte 以二进制的方式计算,即 $2^{30} = 1,073,741,824$ 。(因为 Windows 对 GB 这个信息计量单位的误用,因此在 Windows 中显示的 "1GB",其实应是指 "1GiB",但 Windows 却显示为 "1GB",而常造成误解。误用会普遍化的一大因素,是因为 Windows 的操作系统占有率高),由于两种换算方法的不同,使容量在计算上相差了 7.3%,所以常有 Windows 系统报告的容量比硬盘标示的容量还要小的情况发生。但在苹果公司的 OS X 操作系统中,对于存储设备的容量计算方式与硬盘厂商一致,均为 1GB = 1,000,000,000 ( $10^{9}$ ) 字节的十进制,避免了计算和使用上的麻烦。\n—— 维基百科 - Gibibyte,https://zh.wikipedia.org/wiki/Gibibyte\n\nK、M、G 都是 KB、MB、GB 的简称。由于混淆已经普遍化,Gigabyte 往往是指 Gibibyte,所以平时我们说的 1 兆存储就是 1M(MB),1G 存储就是 1GB)。我们的照片一般是 104KB、209KB、1.45MB、2.45MB、3.32MB 等等。\n在说明其他储存单位的换算前,我们来看看两个标准:SI、IEC。\n国际单位制(SI)\n国际单位制(简称 SI,来自于法语 Système International d\'Unités),是世界上最普遍采用的标准度量系统。国际单位制以七个基本单位(米(m),千克(kg),秒(s),安培(A),开尔文(K),摩尔(mol),坎德拉(cd))为基础,由此建立起一系列相互换算关系明确的"一致单位"。另有二十个基于十进制的词头,当加在单位名称或符号前的时候,可用于表达该单位的倍数或分数。\n国际电工委员会(IEC)\n国际电工委员会(IEC, International Electrotechnical Commission)成立于 1906 年,至今已有 90 多年的历史。它是世界上成立最早的国际性电工标准化机构,负责有关电气工程和电子工程领域中的国际标准化工作。\nIEC 的宗旨是,促进电气、电子工程领域中标准化及有关问题的国际合作,增进国际间的相互了解。为实现这一目的,IEC 出版包括国际标准在内的各种出版物,并希望各成员在本国条件允许的情况下,在本国的标准化工作中使用这些标准。\n目前 IEC 的工作领域已由单纯研究电气设备、电机的名词术语和功率等问题扩展到电子、电力、微电子及其应用、通讯、视听、机器人、信息技术、新型医疗器械和核仪表等电工技术的各个方面。IEC 标准的权威性是世界公认的,截止到 2008 年 12 月底,IEC 已制定了 5425 个国际标准。\n不同标准下储存单位的次方单位 ( $2^{10}=1024$ ):\n\n比特率单位\n在电信和计算领域,比特率(Bit rate)是指单位时间内传输送或处理的比特的数量。比特率经常在电信领域用作连接速度、传输速度、信息传输速率和数字带宽容量的同义词。\n在数字多媒体领域,比特率是单位时间播放连续的媒体如压缩后的音频或视频的比特数量。在这个意义上讲,它相当于术语数字带宽消耗量,或吞吐量。\n比特率规定使用"比特每秒"(bit/s 或 bps)为单位,经常和国际单位制词头关联在一起:\n\n\nbps(bit/s),即 bit pro second(位每秒);\n\n\nKbps(Kbit/s),即 Kilobit pro second(千位每秒);\n\n\nMbps(Mbit/s),即 Milionbit pro second(百万位每秒)。\n\n\n其中,bit 即比特,通常用 b(小写)表示,指一位二进制位,Milionbit=1000Kilobit=1000 000bit,所以 1Mbps=1000 000bps;\nbps 和 Bps\nbps 是通常用来衡量带宽的单位,常见于表示数据机及网络通讯的传输速率,指每秒钟传输的二进制位数。例如 GigabitEthernet 端口。\n5 minute input rate 38410000 bits/sec, 6344 packets/sec\n382410000 bits/sec = 382.41Mbps\n\n通常电脑(软件)上显示的上传下载速度(如下面的阿里云 OSSBrowser、Google Chrome 数据下载速度),则是指每秒种传输的字节数(Byte)通常用 B(大写)表示:MB 即百万字节也称兆字节;KB 即千字节;B 即字节。\n\n\n1B=8b\n\n\n1MB=1024KB=1024*1024B\n\n\n1Mbps=1000Kbps=1000/8KBps=125KBps\n\n\n我们通常说的 1M 带宽即指 1Mbps,因此 1M 的带宽下载的速度一般不会超过 125KB 每秒。2M、3M 带宽的下载速度分别不会超过 250KB、375KB 每秒。\n\n数据传输速率的衡量单位 K 是十进制含义,但数据存储的 K 是 2 进制含义。\n1kbit/s 就是 1000bit/s,而 KB 是 1024 个字节,注意 KB(KByte) 和 kbit 的区别,另外,数据传输速率的单位是 bit/s 记作:bps 。\n在实际应用中:\n\n\n1kbps=1000bps\n\n\n1Mbps=1000,000bps\n\n\n1bps=0.000001bps\n\n\n1Mbps 与 1m/s 是有区别的,1m/s 指的是 1024KB/s,而 1Mbps 指的是(1000/8)KB/s 也就是 125KB/S。\n记住 K 和 k 是没区别的 \xa0,区别在于 bps 属于位每秒的单位,而 m/s ,KB/s 这两个属于字节每秒的单位,一字节等于 8 位,即 1k=8b。\n兆碱基\n所以,在文章开头提到的 DNA 序列的 100 万个碱基数据(兆碱基)大致相当于计算机 1 兆的存储空间。其实也就是这么计算来得:\n一个碱基就是一个英文字母,而一个英文字母是 1 个字节(Byte),所以 100 万个碱基就是 1000,000 Byte。按照 SI 国际单位的十进制标准,正好相当于 1 MB,如果按照 IEC 国际电工委员会的二进制标准,应该为:1000,000 / 1024 /1024 ≈ 0.95 MB,则是大致相当于计算机 1 兆的存储空间。\n参考资料\n\nWiki: Gibibyte,维基百科\nWiki:比特率,维基百科\n沙翁,《什么是 Mbps、Kbps、bps、kb、mb 及其换算和区别》,博客园\n大任 Dren,《bit、Byte、bps、Bps、pps、Gbps 的单位详细说明及换算》,CSDN-专业 IT 技术社区', 'bodyHTML': '

生物信息很多文章都提到 DNA 序列的 100 万个碱基数据(兆碱基)大致相当于计算机 1 兆的存储空间。借着这个问题,我们今天来聊一聊计算机存储和数据传输中 Kb、KB、Bps、bps 的一些区别,分析一下所谓的兆碱基到底是使用哪一种标准(单位)怎么计算出来的。

\n\n

计算机存储容量单位

\n

Bit (binary digit):亦称二进制位,指二进制中的一位,是信息的最小单位。位的值只会是 0 或 1。虽然计算机也提供对位的判断和操作,但是计算机指令一般以字节(Byte)为单位。在大多数的计算机系统中,八位是一个字节。一位的值通常以存储电容是否带电来衡量。

\n

B (Byte):字节。8 个二进制位构成 1 个"字节(Byte)",它是电脑存储空间的基本计量单位。1 字节 (Byte)=8(bit) 位,就是有 8 个二进制数组成。1 个英文字符是 1 个字节,也就是 1B;1 个汉字为 2 个字符,也就是 2B。

\n

GB (Gigabyte):吉字节,是一种十进制的信息计量单位。Gibibyte(giga binary byte 的缩写)则是二进制信息计量的一个单位,简称 GiB。吉字节(Gigabyte)常容易和二进制的信息计量单位 Gibibyte 混淆。

\n
\n

Gibibyte 与 Gigabyte 常常被混淆,前者的计算方式是二进制,后者的计算方式是十进制。现今的计算上,常把 Gigabyte 以二进制的方式计算,即 $2^{30} = 1,073,741,824$ 。(因为 Windows 对 GB 这个信息计量单位的误用,因此在 Windows 中显示的 "1GB",其实应是指 "1GiB",但 Windows 却显示为 "1GB",而常造成误解。误用会普遍化的一大因素,是因为 Windows 的操作系统占有率高),由于两种换算方法的不同,使容量在计算上相差了 7.3%,所以常有 Windows 系统报告的容量比硬盘标示的容量还要小的情况发生。但在苹果公司的 OS X 操作系统中,对于存储设备的容量计算方式与硬盘厂商一致,均为 1GB = 1,000,000,000 ( $10^{9}$ ) 字节的十进制,避免了计算和使用上的麻烦。

\n

—— 维基百科 - Gibibyte,https://zh.wikipedia.org/wiki/Gibibyte

\n
\n

K、M、G 都是 KB、MB、GB 的简称。由于混淆已经普遍化,Gigabyte 往往是指 Gibibyte,所以平时我们说的 1 兆存储就是 1M(MB),1G 存储就是 1GB)。我们的照片一般是 104KB、209KB、1.45MB、2.45MB、3.32MB 等等。

\n

在说明其他储存单位的换算前,我们来看看两个标准:SI、IEC。

\n

国际单位制(SI)

\n

国际单位制(简称 SI,来自于法语 Système International d\'Unités),是世界上最普遍采用的标准度量系统。国际单位制以七个基本单位(米(m),千克(kg),秒(s),安培(A),开尔文(K),摩尔(mol),坎德拉(cd))为基础,由此建立起一系列相互换算关系明确的"一致单位"。另有二十个基于十进制的词头,当加在单位名称或符号前的时候,可用于表达该单位的倍数或分数。

\n

国际电工委员会(IEC)

\n

国际电工委员会(IEC, International Electrotechnical Commission)成立于 1906 年,至今已有 90 多年的历史。它是世界上成立最早的国际性电工标准化机构,负责有关电气工程和电子工程领域中的国际标准化工作。

\n

IEC 的宗旨是,促进电气、电子工程领域中标准化及有关问题的国际合作,增进国际间的相互了解。为实现这一目的,IEC 出版包括国际标准在内的各种出版物,并希望各成员在本国条件允许的情况下,在本国的标准化工作中使用这些标准。

\n

目前 IEC 的工作领域已由单纯研究电气设备、电机的名词术语和功率等问题扩展到电子、电力、微电子及其应用、通讯、视听、机器人、信息技术、新型医疗器械和核仪表等电工技术的各个方面。IEC 标准的权威性是世界公认的,截止到 2008 年 12 月底,IEC 已制定了 5425 个国际标准。

\n

不同标准下储存单位的次方单位 ( $2^{10}=1024$ ):

\n

字节的次方单位

\n

比特率单位

\n

在电信和计算领域,比特率(Bit rate)是指单位时间内传输送或处理的比特的数量。比特率经常在电信领域用作连接速度、传输速度、信息传输速率和数字带宽容量的同义词。

\n

在数字多媒体领域,比特率是单位时间播放连续的媒体如压缩后的音频或视频的比特数量。在这个意义上讲,它相当于术语数字带宽消耗量,或吞吐量。

\n

比特率规定使用"比特每秒"(bit/s 或 bps)为单位,经常和国际单位制词头关联在一起:

\n
    \n
  • \n

    bps(bit/s),即 bit pro second(位每秒);

    \n
  • \n
  • \n

    Kbps(Kbit/s),即 Kilobit pro second(千位每秒);

    \n
  • \n
  • \n

    Mbps(Mbit/s),即 Milionbit pro second(百万位每秒)。

    \n
  • \n
\n

其中,bit 即比特,通常用 b(小写)表示,指一位二进制位,Milionbit=1000Kilobit=1000 000bit,所以 1Mbps=1000 000bps;

\n

bps 和 Bps

\n

bps 是通常用来衡量带宽的单位,常见于表示数据机及网络通讯的传输速率,指每秒钟传输的二进制位数。例如 GigabitEthernet 端口。

\n
5 minute input rate 38410000 bits/sec, 6344 packets/sec\n382410000 bits/sec = 382.41Mbps\n
\n

通常电脑(软件)上显示的上传下载速度(如下面的阿里云 OSSBrowser、Google Chrome 数据下载速度),则是指每秒种传输的字节数(Byte)通常用 B(大写)表示:MB 即百万字节也称兆字节;KB 即千字节;B 即字节。

\n
    \n
  • \n

    1B=8b

    \n
  • \n
  • \n

    1MB=1024KB=1024*1024B

    \n
  • \n
  • \n

    1Mbps=1000Kbps=1000/8KBps=125KBps

    \n
  • \n
\n

我们通常说的 1M 带宽即指 1Mbps,因此 1M 的带宽下载的速度一般不会超过 125KB 每秒。2M、3M 带宽的下载速度分别不会超过 250KB、375KB 每秒。

\n

download-byte-rate

\n

数据传输速率的衡量单位 K 是十进制含义,但数据存储的 K 是 2 进制含义。

\n

1kbit/s 就是 1000bit/s,而 KB 是 1024 个字节,注意 KB(KByte) 和 kbit 的区别,另外,数据传输速率的单位是 bit/s 记作:bps 。

\n

在实际应用中:

\n
    \n
  • \n

    1kbps=1000bps

    \n
  • \n
  • \n

    1Mbps=1000,000bps

    \n
  • \n
  • \n

    1bps=0.000001bps

    \n
  • \n
\n

1Mbps 与 1m/s 是有区别的,1m/s 指的是 1024KB/s,而 1Mbps 指的是(1000/8)KB/s 也就是 125KB/S。

\n

记住 K 和 k 是没区别的 \xa0,区别在于 bps 属于位每秒的单位,而 m/s ,KB/s 这两个属于字节每秒的单位,一字节等于 8 位,即 1k=8b。

\n

兆碱基

\n

所以,在文章开头提到的 DNA 序列的 100 万个碱基数据(兆碱基)大致相当于计算机 1 兆的存储空间。其实也就是这么计算来得:

\n

一个碱基就是一个英文字母,而一个英文字母是 1 个字节(Byte),所以 100 万个碱基就是 1000,000 Byte。按照 SI 国际单位的十进制标准,正好相当于 1 MB,如果按照 IEC 国际电工委员会的二进制标准,应该为:1000,000 / 1024 /1024 ≈ 0.95 MB,则是大致相当于计算机 1 兆的存储空间。

\n

参考资料

\n', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.4-知识'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '沉浸式双语网页翻译扩展', 'number': 19, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/19', 'createdAt': '2023-11-23T01:07:46Z', 'lastEditedAt': '2024-04-19T08:57:37Z', 'updatedAt': '2024-04-19T08:57:37Z', 'body': '向大家极力推荐这个插件:**沉浸式双语网页翻译扩展**,浏览器翻译神器,而且**完全免费**!\r\n\r\n- **GitHub:** [https://github.com/immersive-translate/immersive-translate](https://github.com/immersive-translate/immersive-translate)\r\n- 如果你是 **Mac** 系统,推荐:[https://github.com/ripperhe/Bob](https://github.com/ripperhe/Bob)\r\n\r\n\r\n\r\n![image.png](https://shub.weiyan.tech/yuque/elog-cookbook-img/FtAZvqEDdgc3yfpbqwRq40MUEfld.png)\r\n\r\n**截图**\r\n![Twitter 翻译](https://shub.weiyan.tech/yuque/elog-cookbook-img/FpC4e5Sf_G5YT9bzCWSTl4oBIBVO.png "Twitter 翻译")\r\n\r\n![pdf 文件翻译](https://shub.weiyan.tech/yuque/elog-cookbook-img/FpImmIXzUhUNXaD-OgDI1AArm2eu.png "pdf 文件翻译")\r\n\r\n![Reddit 高亮译文样式](https://shub.weiyan.tech/yuque/elog-cookbook-img/FuFqmDqRNOZl_es2sVoRkmeMDAar.png "Reddit 高亮译文样式")\r\n', 'bodyText': '向大家极力推荐这个插件:沉浸式双语网页翻译扩展,浏览器翻译神器,而且完全免费!\n\nGitHub: https://github.com/immersive-translate/immersive-translate\n如果你是 Mac 系统,推荐:https://github.com/ripperhe/Bob\n\n\n\n截图', 'bodyHTML': '

向大家极力推荐这个插件:沉浸式双语网页翻译扩展,浏览器翻译神器,而且完全免费

\n\n\n

image.png

\n

截图
\nTwitter 翻译

\n

pdf 文件翻译

\n

Reddit 高亮译文样式

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '跨端博客解决方案 Elog 使用', 'number': 18, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/18', 'createdAt': '2023-11-23T01:04:15Z', 'lastEditedAt': None, 'updatedAt': '2024-01-04T05:44:58Z', 'body': 'Elog () —— 开放式跨平台博客解决方案,随意组合写作平台 (语雀/Notion/FlowUs) 和部署平台 (Hexo/Vitepress 等 。\r\n\r\n\r\n\r\n主要配置文件 **elog.config.js**:\r\n\r\n```javascript\r\nmodule.exports = {\r\n write: {\r\n platform: "yuque",\r\n yuque: {\r\n token: process.env.YUQUE_TOKEN,\r\n baseUrl: "",\r\n login: process.env.YUQUE_LOGIN,\r\n repo: process.env.YUQUE_REPO,\r\n onlyPublic: false,\r\n onlyPublished: true,\r\n },\r\n notion: {\r\n token: process.env.NOTION_TOKEN,\r\n databaseId: process.env.NOTION_DATABASE_ID,\r\n filter: true, // {property: \'status\', select: {equals: \'已发布\'}}\r\n sorts: true, // [{timestamp: \'created_time\', direction: \'descending\'}],\r\n catalog: false,\r\n },\r\n flowus: {\r\n tablePageId: process.env.FLOWUS_TABLE_PAGE_ID,\r\n filter: true, // {property: \'status\',value: \'已发布\'}\r\n sort: true, // { property: \'createdAt\', direction: \'descending\' }\r\n catalog: false,\r\n },\r\n },\r\n deploy: {\r\n platform: "local",\r\n local: {\r\n outputDir: "./Cookbook",\r\n filename: "title", //生成文档的命名格式,取值 urlname|title\r\n format: "markdown",\r\n catalog: true, //是否按照目录生成文档\r\n formatExt: "",\r\n },\r\n confluence: {\r\n user: process.env.CONFLUENCE_USER,\r\n password: process.env.CONFLUENCE_PASSWORD,\r\n baseUrl: process.env.CONFLUENCE_BASE_URL,\r\n spaceKey: process.env.CONFLUENCE_SPACE_KEY,\r\n rootPageId: process.env.CONFLUENCE_ROOT_PAGE_ID, // 可选\r\n formatExt: "", // 可选\r\n },\r\n },\r\n image: {\r\n enable: true,\r\n platform: "local",\r\n local: {\r\n outputDir: "./Images", //本地图片保存目录\r\n prefixKey: "/cookbook", //替换图片的url前缀,如 ![image.png](/cookbook/xxxx.png)\r\n },\r\n oss: {\r\n secretId: process.env.OSS_SECRET_ID,\r\n secretKey: process.env.OSS_SECRET_KEY,\r\n bucket: process.env.OSS_BUCKET,\r\n region: process.env.OSS_REGION,\r\n host: process.env.OSS_HOST,\r\n prefixKey: "",\r\n secretExt: "", // 可选\r\n },\r\n cos: {\r\n secretId: process.env.COS_SECRET_ID,\r\n secretKey: process.env.COS_SECRET_KEY,\r\n bucket: process.env.COS_BUCKET,\r\n region: process.env.COS_REGION,\r\n host: process.env.COS_HOST,\r\n prefixKey: "",\r\n secretExt: "", // 可选\r\n },\r\n qiniu: {\r\n secretId: process.env.QINIU_SECRET_ID,\r\n secretKey: process.env.QINIU_SECRET_KEY,\r\n bucket: process.env.QINIU_BUCKET,\r\n region: process.env.QINIU_REGION,\r\n host: process.env.QINIU_HOST,\r\n prefixKey: "",\r\n secretExt: "", // 可选\r\n },\r\n upyun: {\r\n user: process.env.UPYUN_USER,\r\n password: process.env.UPYUN_PASSWORD,\r\n bucket: process.env.UPYUN_BUCKET,\r\n host: process.env.UPYUN_HOST,\r\n prefixKey: "",\r\n secretExt: "", // 可选\r\n },\r\n github: {\r\n user: process.env.GITHUB_USER,\r\n token: process.env.GITHUB_TOKEN,\r\n repo: process.env.GITHUB_REPO,\r\n branch: "",\r\n host: "",\r\n prefixKey: "",\r\n secretExt: "", // 可选\r\n },\r\n },\r\n};\r\n```\r\n\r\n基于语雀 WebHook 实现实时同步:\r\n', 'bodyText': 'Elog (https://github.com/LetTTGACO/elog) —— 开放式跨平台博客解决方案,随意组合写作平台 (语雀/Notion/FlowUs) 和部署平台 (Hexo/Vitepress 等 。\n\n主要配置文件 elog.config.js:\nmodule.exports = {\n write: {\n platform: "yuque",\n yuque: {\n token: process.env.YUQUE_TOKEN,\n baseUrl: "",\n login: process.env.YUQUE_LOGIN,\n repo: process.env.YUQUE_REPO,\n onlyPublic: false,\n onlyPublished: true,\n },\n notion: {\n token: process.env.NOTION_TOKEN,\n databaseId: process.env.NOTION_DATABASE_ID,\n filter: true, // {property: \'status\', select: {equals: \'已发布\'}}\n sorts: true, // [{timestamp: \'created_time\', direction: \'descending\'}],\n catalog: false,\n },\n flowus: {\n tablePageId: process.env.FLOWUS_TABLE_PAGE_ID,\n filter: true, // {property: \'status\',value: \'已发布\'}\n sort: true, // { property: \'createdAt\', direction: \'descending\' }\n catalog: false,\n },\n },\n deploy: {\n platform: "local",\n local: {\n outputDir: "./Cookbook",\n filename: "title", //生成文档的命名格式,取值 urlname|title\n format: "markdown",\n catalog: true, //是否按照目录生成文档\n formatExt: "",\n },\n confluence: {\n user: process.env.CONFLUENCE_USER,\n password: process.env.CONFLUENCE_PASSWORD,\n baseUrl: process.env.CONFLUENCE_BASE_URL,\n spaceKey: process.env.CONFLUENCE_SPACE_KEY,\n rootPageId: process.env.CONFLUENCE_ROOT_PAGE_ID, // 可选\n formatExt: "", // 可选\n },\n },\n image: {\n enable: true,\n platform: "local",\n local: {\n outputDir: "./Images", //本地图片保存目录\n prefixKey: "/cookbook", //替换图片的url前缀,如 ![image.png](/cookbook/xxxx.png)\n },\n oss: {\n secretId: process.env.OSS_SECRET_ID,\n secretKey: process.env.OSS_SECRET_KEY,\n bucket: process.env.OSS_BUCKET,\n region: process.env.OSS_REGION,\n host: process.env.OSS_HOST,\n prefixKey: "",\n secretExt: "", // 可选\n },\n cos: {\n secretId: process.env.COS_SECRET_ID,\n secretKey: process.env.COS_SECRET_KEY,\n bucket: process.env.COS_BUCKET,\n region: process.env.COS_REGION,\n host: process.env.COS_HOST,\n prefixKey: "",\n secretExt: "", // 可选\n },\n qiniu: {\n secretId: process.env.QINIU_SECRET_ID,\n secretKey: process.env.QINIU_SECRET_KEY,\n bucket: process.env.QINIU_BUCKET,\n region: process.env.QINIU_REGION,\n host: process.env.QINIU_HOST,\n prefixKey: "",\n secretExt: "", // 可选\n },\n upyun: {\n user: process.env.UPYUN_USER,\n password: process.env.UPYUN_PASSWORD,\n bucket: process.env.UPYUN_BUCKET,\n host: process.env.UPYUN_HOST,\n prefixKey: "",\n secretExt: "", // 可选\n },\n github: {\n user: process.env.GITHUB_USER,\n token: process.env.GITHUB_TOKEN,\n repo: process.env.GITHUB_REPO,\n branch: "",\n host: "",\n prefixKey: "",\n secretExt: "", // 可选\n },\n },\n};\n基于语雀 WebHook 实现实时同步:https://github.com/LetTTGACO/serverless-api', 'bodyHTML': '

Elog (https://github.com/LetTTGACO/elog) —— 开放式跨平台博客解决方案,随意组合写作平台 (语雀/Notion/FlowUs) 和部署平台 (Hexo/Vitepress 等 。

\n\n

主要配置文件 elog.config.js

\n
module.exports = {\n  write: {\n    platform: "yuque",\n    yuque: {\n      token: process.env.YUQUE_TOKEN,\n      baseUrl: "",\n      login: process.env.YUQUE_LOGIN,\n      repo: process.env.YUQUE_REPO,\n      onlyPublic: false,\n      onlyPublished: true,\n    },\n    notion: {\n      token: process.env.NOTION_TOKEN,\n      databaseId: process.env.NOTION_DATABASE_ID,\n      filter: true, // {property: \'status\', select: {equals: \'已发布\'}}\n      sorts: true, // [{timestamp: \'created_time\', direction: \'descending\'}],\n      catalog: false,\n    },\n    flowus: {\n      tablePageId: process.env.FLOWUS_TABLE_PAGE_ID,\n      filter: true, // {property: \'status\',value: \'已发布\'}\n      sort: true, // { property: \'createdAt\', direction: \'descending\' }\n      catalog: false,\n    },\n  },\n  deploy: {\n    platform: "local",\n    local: {\n      outputDir: "./Cookbook",\n      filename: "title", //生成文档的命名格式,取值 urlname|title\n      format: "markdown",\n      catalog: true, //是否按照目录生成文档\n      formatExt: "",\n    },\n    confluence: {\n      user: process.env.CONFLUENCE_USER,\n      password: process.env.CONFLUENCE_PASSWORD,\n      baseUrl: process.env.CONFLUENCE_BASE_URL,\n      spaceKey: process.env.CONFLUENCE_SPACE_KEY,\n      rootPageId: process.env.CONFLUENCE_ROOT_PAGE_ID, // 可选\n      formatExt: "", // 可选\n    },\n  },\n  image: {\n    enable: true,\n    platform: "local",\n    local: {\n      outputDir: "./Images", //本地图片保存目录\n      prefixKey: "/cookbook", //替换图片的url前缀,如 ![image.png](/cookbook/xxxx.png)\n    },\n    oss: {\n      secretId: process.env.OSS_SECRET_ID,\n      secretKey: process.env.OSS_SECRET_KEY,\n      bucket: process.env.OSS_BUCKET,\n      region: process.env.OSS_REGION,\n      host: process.env.OSS_HOST,\n      prefixKey: "",\n      secretExt: "", // 可选\n    },\n    cos: {\n      secretId: process.env.COS_SECRET_ID,\n      secretKey: process.env.COS_SECRET_KEY,\n      bucket: process.env.COS_BUCKET,\n      region: process.env.COS_REGION,\n      host: process.env.COS_HOST,\n      prefixKey: "",\n      secretExt: "", // 可选\n    },\n    qiniu: {\n      secretId: process.env.QINIU_SECRET_ID,\n      secretKey: process.env.QINIU_SECRET_KEY,\n      bucket: process.env.QINIU_BUCKET,\n      region: process.env.QINIU_REGION,\n      host: process.env.QINIU_HOST,\n      prefixKey: "",\n      secretExt: "", // 可选\n    },\n    upyun: {\n      user: process.env.UPYUN_USER,\n      password: process.env.UPYUN_PASSWORD,\n      bucket: process.env.UPYUN_BUCKET,\n      host: process.env.UPYUN_HOST,\n      prefixKey: "",\n      secretExt: "", // 可选\n    },\n    github: {\n      user: process.env.GITHUB_USER,\n      token: process.env.GITHUB_TOKEN,\n      repo: process.env.GITHUB_REPO,\n      branch: "",\n      host: "",\n      prefixKey: "",\n      secretExt: "", // 可选\n    },\n  },\n};
\n

基于语雀 WebHook 实现实时同步:https://github.com/LetTTGACO/serverless-api

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'NCBI API 使用', 'number': 17, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/17', 'createdAt': '2023-11-21T06:44:23Z', 'lastEditedAt': None, 'updatedAt': '2023-11-21T06:44:24Z', 'body': '参考:https://www.ncbi.nlm.nih.gov/books/NBK25499/', 'bodyText': '参考:https://www.ncbi.nlm.nih.gov/books/NBK25499/', 'bodyHTML': '

参考:https://www.ncbi.nlm.nih.gov/books/NBK25499/

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.1-生信'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '留言与建议', 'number': 16, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/16', 'createdAt': '2023-11-09T07:42:48Z', 'lastEditedAt': '2024-10-23T06:29:59Z', 'updatedAt': '2024-10-23T06:30:45Z', 'body': '如果你通过本人的博文/平台学到了一点东西,那么对我最好的奖赏就是请你也尝试教我些东西。你可以通过邮箱、微信,或者移步到 “[GitHub Discussions](https://github.com/shenweiyan/Knowledge-Garden/discussions/16)” 写下您的建议,或者向我提问。\r\n\r\n感谢你的一路支持!\r\n\r\n\r\n📢 如果给我发邮件,或者通过微信添加好友,请写上您的**真名实姓**,让我感受到一个**真实的人的气息**。我不太愿意跟**网名**打交道,对于那些不知来路、上来就问问题的微信和邮件,我通常会直接忽略。\r\n\r\n- 微信:**ishenweiyan**(请备注真实姓名,谢谢)\r\n- 邮箱:**shen@weiyan.tech**\r\n\r\n

\r\n feedback\r\n

', 'bodyText': '如果你通过本人的博文/平台学到了一点东西,那么对我最好的奖赏就是请你也尝试教我些东西。你可以通过邮箱、微信,或者移步到 “GitHub Discussions” 写下您的建议,或者向我提问。\n感谢你的一路支持!\n📢 如果给我发邮件,或者通过微信添加好友,请写上您的真名实姓,让我感受到一个真实的人的气息。我不太愿意跟网名打交道,对于那些不知来路、上来就问问题的微信和邮件,我通常会直接忽略。\n\n微信:ishenweiyan(请备注真实姓名,谢谢)\n邮箱:shen@weiyan.tech', 'bodyHTML': '

如果你通过本人的博文/平台学到了一点东西,那么对我最好的奖赏就是请你也尝试教我些东西。你可以通过邮箱、微信,或者移步到 “GitHub Discussions” 写下您的建议,或者向我提问。

\n

感谢你的一路支持!

\n

📢 如果给我发邮件,或者通过微信添加好友,请写上您的真名实姓,让我感受到一个真实的人的气息。我不太愿意跟网名打交道,对于那些不知来路、上来就问问题的微信和邮件,我通常会直接忽略。

\n
    \n
  • 微信:ishenweiyan(请备注真实姓名,谢谢)
  • \n
  • 邮箱:shen@weiyan.tech
  • \n
\n

\n feedback\n

', 'author': {'login': 'shenweiyan'}, 'category': {'name': 'x.x-留言'}, 'labels': {'nodes': []}, 'comments': {'nodes': [{'body': '想了一下,还是增加一个留言的页面吧 >.<', 'author': {'login': 'shenweiyan'}}, {'body': 'hello', 'author': {'login': 'vbskycn'}}, {'body': '我也去整个webstack导航~~ 一入hugo深似海,从此wp是路人。', 'author': {'login': 'daoyuc'}}]}}, {'title': '基于 GitHub Discussions 的博客与站点', 'number': 15, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/15', 'createdAt': '2023-11-09T05:38:01Z', 'lastEditedAt': '2023-11-23T07:06:53Z', 'updatedAt': '2024-01-04T05:44:37Z', 'body': 'GitHub Discussions 是一个可以在每个 GitHub 仓库上启用的论坛。它使开发者能够轻松地讨论新功能,从社区获得反馈,创建投票,发布公告等。这里搜集了一些基于 GitHub Discussions 的博客与站点,以供参考。\r\n\r\n\r\n\r\n- [Hakuba](https://github.com/YeungKC/Hakuba) - 一个通过 Github Discussion 驱动的 Blog 启动器\r\n\r\n- [GG](https://github.com/lencx/gg) - Gatsby + GitHub,好像不支持 MathJax,也不见怎么维护了\r\n - [lencx.tech](https://lencx.tech/#/)\r\n - [gg-discussions](https://shenweiyan.github.io/gg-discussions/),个人尝试对页面进行了一些调整\r\n\r\n- [Pure](https://github.com/LeetaoGoooo/pure) 一个基于 Github Discussion 的极简博客', 'bodyText': 'GitHub Discussions 是一个可以在每个 GitHub 仓库上启用的论坛。它使开发者能够轻松地讨论新功能,从社区获得反馈,创建投票,发布公告等。这里搜集了一些基于 GitHub Discussions 的博客与站点,以供参考。\n\n\n\nHakuba - 一个通过 Github Discussion 驱动的 Blog 启动器\n\n\nGG - Gatsby + GitHub,好像不支持 MathJax,也不见怎么维护了\n\nlencx.tech\ngg-discussions,个人尝试对页面进行了一些调整\n\n\n\nPure 一个基于 Github Discussion 的极简博客', 'bodyHTML': '

GitHub Discussions 是一个可以在每个 GitHub 仓库上启用的论坛。它使开发者能够轻松地讨论新功能,从社区获得反馈,创建投票,发布公告等。这里搜集了一些基于 GitHub Discussions 的博客与站点,以供参考。

\n\n
    \n
  • \n

    Hakuba - 一个通过 Github Discussion 驱动的 Blog 启动器

    \n
  • \n
  • \n

    GG - Gatsby + GitHub,好像不支持 MathJax,也不见怎么维护了

    \n\n
  • \n
  • \n

    Pure 一个基于 Github Discussion 的极简博客

    \n
  • \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '基于 Mkdocs 的主题与站点', 'number': 14, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/14', 'createdAt': '2023-11-08T03:29:49Z', 'lastEditedAt': '2024-06-03T03:28:50Z', 'updatedAt': '2024-06-03T03:28:50Z', 'body': "鉴于 MkDocs 的诸多优点,让它被很多知名开源项目选中,用于搭建和项目相关的文档网站。比如 Python 里知名的 Web 圈里的 [django-rest-framework](https://sspai.com/link?target=https%3A%2F%2Fwww.django-rest-framework.org%2F)、[FastAPI](https://sspai.com/link?target=https%3A%2F%2Ffastapi.tiangolo.com%2F) 以及基于 Go 编写的云网关代理服务器 [traefik](https://sspai.com/link?target=https%3A%2F%2Fgithub.com%2Ftraefik%2Ftraefik) 等项目的官方文档站点,都是通过 MkDocs 进行搭建。\r\n\r\n\r\n\r\n下面列的是搜集的一些 Mkdocs 主题与站点,以供参考。\r\n\r\n- Hello 算法 - \r\n- FDU-MSC 论坛 - \r\n- Django REST framework - \r\n- FastAPI - \r\n- Chrisjing 的运维之旅精选 - \r\n- 艇仔粥 TingZaiZuk - \r\n- Arisa | Blog - \r\n- 嬉戏实验室 - \r\n- 老胡的周刊 - [weekly.howie6879.com](https://weekly.howie6879.com/)\r\n- Wcowin's Web - \r\n- Jeremy Feng - \r\n- 我的工作学习生活笔记 - \r\n- Power's Wiki - ", 'bodyText': "鉴于 MkDocs 的诸多优点,让它被很多知名开源项目选中,用于搭建和项目相关的文档网站。比如 Python 里知名的 Web 圈里的 django-rest-framework、FastAPI 以及基于 Go 编写的云网关代理服务器 traefik 等项目的官方文档站点,都是通过 MkDocs 进行搭建。\n\n下面列的是搜集的一些 Mkdocs 主题与站点,以供参考。\n\nHello 算法 - https://www.hello-algo.com/\nFDU-MSC 论坛 - https://fdu-msc.github.io/forum/\nDjango REST framework - https://www.django-rest-framework.org/\nFastAPI - https://fastapi.tiangolo.com/\nChrisjing 的运维之旅精选 - http://www.chrisjing.com/\n艇仔粥 TingZaiZuk - https://herointene.github.io/\nArisa | Blog - https://blog.arisa.moe/\n嬉戏实验室 - https://blog.xiiigame.com/\n老胡的周刊 - weekly.howie6879.com\nWcowin's Web - https://wcowin.work/\nJeremy Feng - https://fengchao.pro/\n我的工作学习生活笔记 - https://hellowac.github.io/\nPower's Wiki - https://wiki-power.com/", 'bodyHTML': '

鉴于 MkDocs 的诸多优点,让它被很多知名开源项目选中,用于搭建和项目相关的文档网站。比如 Python 里知名的 Web 圈里的 django-rest-frameworkFastAPI 以及基于 Go 编写的云网关代理服务器 traefik 等项目的官方文档站点,都是通过 MkDocs 进行搭建。

\n\n

下面列的是搜集的一些 Mkdocs 主题与站点,以供参考。

\n', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': [{'name': 'mkdocs'}]}, 'comments': {'nodes': []}}, {'title': 'Python3 源码安装', 'number': 13, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/13', 'createdAt': '2023-11-02T03:05:46Z', 'lastEditedAt': '2024-10-14T09:15:08Z', 'updatedAt': '2024-10-14T09:15:09Z', 'body': '编程,作为生物信息学的一个基础性技能,是任何一个生信工程师都无法绕开话题。也许有些人还在纠结 Perl 和 Python 到底应该学习哪一个,但作为目前最火最流行的编程语言 Python 还是非常值得尝试的。它不但可以进行文本处理,在统计、网站、游戏、爬虫、数据可视化等方面也有非常强大的应用,比起曾经的 Perl 真的强大和全面很多,且比 Perl 更容易入手。不管从长远发展,还是短期需要,学会 Python,看懂 Perl (或者先学 \xa0 Python,后学 Perl) 应该是每一个生信工程必备的基础技能之一。\r\n\r\n工欲善其事,必先利其器。关于 Python 安装教程在网上一搜一大把,但总感觉不够全面,尤其对于中间出现的一些问题的解决方法不尽如人意。鉴于此,本文基于 \xa0CentOS/RHEL Linux 对 Python 的源码编译安装进行了一下简单的总结,记录如下。\r\n\r\n## 安装环境\r\n\r\nRed Hat 6.5 + GCC 4.4.7(GCC-7.3.0 - 此版本 gcc 为手动安装)。\r\n\r\nGCC 高级版本手动或者 `yum` 安装参考以下文章:\r\n- [SCL+Devtoolset 安装与使用笔记 · 语雀](https://www.yuque.com/shenweiyan/cookbook/scl-devtoolset-note)\r\n- [非 root 用户手动编译安装 GCC · 语雀](https://www.yuque.com/shenweiyan/cookbook/linux-gcc-install)\r\n\r\n```bash\r\n$ lsb_release -a\r\nLSB Version: :base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noarch:graphics-4.0-amd64:graphics-4.0-noarch:printing-4.0-amd64:printing-4.0-noarch\r\nDistributor ID: RedHatEnterpriseServer\r\nDescription: Red Hat Enterprise Linux Server release 6.5 (Santiago)\r\nRelease: 6.5\r\nCodename: Santiago\r\n\r\n$ gcc --version\r\ngcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-4)\r\nCopyright (C) 2010 Free Software Foundation, Inc.\r\nThis is free software; see the source for copying conditions. There is NO\r\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\r\n```\r\n\r\n## 解决依赖\r\n\r\n如果您拥有 root 权限,请执以下依赖安装:\r\n\r\n```bash\r\nyum install zlib\r\nyum install zlib-devel\r\nyum install openssl\r\nyum install openssl-devel\r\nyum install libffi\r\nyum install libffi-devel\r\nyum install readline readline-devel sqlite sqlite-devel tk-devel\r\n```\r\n\r\n| 缺少库名称 | 安装命令 |\r\n| ---------- | ----------------------------------------------------- |\r\n| \\_uuid | yum install libuuid-devel |\r\n| readline | yum install readline-devel |\r\n| \\_tkinter | yum install tk-devel |\r\n| \\_ffi | yum install libffi-devel |\r\n| \\_curses | yum install ncurses-libs |\r\n| \\_sqlite | yum install sqlite-devel |\r\n| \\_bz2 | yum isntall bzip2-devel |\r\n| \\_ssl | yum install openssl-devel |\r\n| \\_gdbm | yum install gdbm-devel |\r\n| \\_dbi | yum install libdbi-devel |\r\n| \\_zlib | yum install zlib-devel |\r\n| lzma | yum install xz-develyum install python-backports-lzma |\r\n\r\n如果您没有 root 权限,可以参考《[手把手教你在 Linux 源码安装最新版本的 R](https://www.yuque.com/shenweiyan/cookbook/install-latest-r-from-source)》一文,手动一个个去解决以上的依赖。\r\n\r\n### _sqlite3 \r\n\r\n执行 **make** 过程中提示 **_sqlite3 not found**,如下:\r\n\r\n```bash\r\n$ make\r\n......\r\nPython build finished successfully!\r\nThe necessary bits to build these optional modules were not found:\r\n_sqlite3 _ssl\r\nTo find the necessary bits, look in setup.py in detect_modules() for the module\'s name.\r\n\r\nThe following modules found by detect_modules() in setup.py, have been\r\nbuilt by the Makefile instead, as configured by the Setup files:\r\n_abc atexit pwd\r\ntime\r\n```\r\n\r\n#### 系统已安装 sqlite3\r\n\r\n如果执行 **rpm -qa|grep sqlite** 看到 sqlite 和 sqlite-devel 都已经安装(libsqlite3.so 默认保存在 /usr/lib64 下; `sqlite3.h` 默认保存在 `/usr/include` 下)。\r\n\r\n```bash\r\n$ sqlite3 -version\r\n3.6.20\r\n\r\n$ ll /usr/lib64/libsqlite3.so\r\nlrwxrwxrwx 1 root root 19 Apr 23 2015 /usr/lib64/libsqlite3.so -> libsqlite3.so.0.8.6\r\n\r\n$ ll /usr/include/sqlite3.h\r\n-rw-r--r-- 1 root root 263K Nov 25 2009 /usr/include/sqlite3.h\r\n```\r\n\r\n但是,执行 `make` 依然出现以上报错,参考下面的方法《[python build from source: cannot build optional module sqlite3 - Stack Overflow](https://stackoverflow.com/questions/32779768/python-build-from-source-cannot-build-optional-module-sqlite3)》。\r\n\r\n#### 手动安装 sqlite3\r\n\r\n```bash\r\n$ wget https://www.sqlite.org/2021/sqlite-autoconf-3360000.tar.gz --no-check-certificate\r\n$ tar zvxf sqlite-autoconf-3360000.tar.gz\r\n$ cd sqlite-autoconf-3360000\r\n$ ./configure --prefix=/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0\r\n$ make\r\n$ make install\r\n```\r\n\r\n#### 配置 sqlite3\r\n\r\n1. 配置环境\r\n\r\n```bash\r\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/lib:$LD_LIBRARY_PATH\r\n```\r\n2. 调整源码或编译\r\n\r\n对于 3.11.x 以上版本的 Python 可以在 `configure` 指定自定义安装的 sqlite3 路径解决 `_sqlite3` 依赖。\r\n```\r\n./configure ... \\\r\n LDFLAGS="-L/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/lib" \\\r\n CPPFLAGS="-I/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/include" \r\n```\r\n\r\n有些低版本的 Python (如 3.7) 可能需要再源码文件中加入 `sqlite3.h` 的文件路径。\r\n\r\n1. 找到 **sqlite3.h** 文件的保存目录。\r\n2. 修改 **setup.py** 文件,在 sqlite_inc_paths 中加上 sqlite3.h 的文件路径。\r\n\r\n```bash\r\nsqlite_inc_paths = [ \'/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/include\',\r\n \'/usr/include\',\r\n \'/usr/include/sqlite\',\r\n \'/usr/include/sqlite3\',\r\n \'/usr/local/include\',\r\n \'/usr/local/include/sqlite\',\r\n \'/usr/local/include/sqlite3\',\r\n ]\r\n```\r\n\r\n\r\n### _ssl \r\n\r\nPython3 需要引用 `openssl`\xa0 模块,但是 python3.7+ 在 CentOS 中要求的 openssl 版本最低为 1.0.2,而 CentOS 默认的为 1.0.1(CentOS-6.x 通过 `yum`\xa0 源安装的 openssl 的最高版本是 1.0.1),所以需要手动更新 openssl。\r\n\r\n对于 openssl 版本的选择,建议至少选择 1.1.1+ 版本:\r\n\r\n1. urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the \'ssl\' module is compiled with \'OpenSSL 1.0.2k-fips 26 Jan 2017\'. See: https://github.com/urllib3/urllib3/issues/2168\r\n2. **Python requires an OpenSSL 1.0.2 or 1.1 compatible libssl with X509_VERIFY_PARAM_set1_host().**\r\n\r\n```bash\r\n# 下载\r\nwget http://www.openssl.org/source/openssl-1.1.1.tar.gz\r\n\r\n# 解压缩\r\ntar -zxvf openssl-1.1.1.tar.gz\r\n\r\n# 进入目录安装\r\ncd openssl-1.1.1\r\n\r\n# 进行配置下,自定义\r\n./config --prefix=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1 shared zlib\r\n\r\n# 编译并安装\r\nmake && make install\r\n\r\n# 配置到用户环境变量,随处使用\r\necho "export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1/lib:$LD_LIBRARY_PATH" >> $HOME/.bashrc\r\n\r\n# 是环境变量配置生效\r\nsource $HOME/.bashrc\r\n```\r\n\r\n**请注意:**\r\n\r\n1. **openssl**\xa0编译(config)的时候 **必须要加上 shared\xa0 参数**,否者源码安装 Python 即使添加了 `--with-openssl`\xa0的自定义路径,依然会导致 `Could not build the ssl module!`\xa0报错!\r\n2. 从 \xa0下载的源码 openssl-1.0.2s、openssl-1.0.2m,包括 \xa0CentOS-7.5 使用 `yum`\xa0安装的最高版本的 openssl-1.0.2k 目前发现依然会导致 `Could not build the ssl module`\xa0,建议从 \xa0下载 1.1.1 的源码编译安装。\r\n\r\n最后,在 Python 执行 `configure` 的时候指定 openssl 的相关参数:\r\n```\r\n./configure ... \\\r\n --with-openssl=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1 \\\r\n --with-openssl-rpath=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1/lib \\\r\n```\r\n\r\n### _tkinter\r\n\r\nTkinter 模块缺失是一个比较棘手的问题,为此专门写了一篇文章来介绍这个问题。\r\n\r\n具体请参考:[Python 中 tkinter 源码安装使用与中文乱码 - Knowledge-Garden#12](https://github.com/shenweiyan/Knowledge-Garden/discussions/12)\r\n\r\n### _dbm\r\n\r\n`_dbm` 和 `_gdbm` 的模块缺失可以通过下面手动的方法解决。\r\n\r\n```\r\nwget https://ftp.gnu.org/gnu/gdbm/gdbm-1.23.tar.gz\r\ntar -zxvf gdbm-1.23.tar.gz\r\n./configure --prefix=/Bioinfo/Pipeline/SoftWare/gdbm-1.23 --enable-libgdbm-compat --enable-debug\r\nmake && make install\r\n```\r\n\r\n最后,增加环境变量,并调整 Python 执行 `configure` 时的参数:\r\n```\r\nexport PATH=/Bioinfo/Pipeline/SoftWare/gdbm-1.23/bin:$PATH\r\nexport LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/gdbm-1.23/lib:$LD_LIBRARY_PATH\r\n\r\n./configure ... \\\r\n LDFLAGS="-L/Bioinfo/Pipeline/SoftWare/gdbm-1.23/lib" \\\r\n CPPFLAGS="-I/Bioinfo/Pipeline/SoftWare/gdbm-1.23/include"\r\n```\r\n\r\n### _lzma \r\n\r\n正常情况下,下面的方法可以解决该问题(如果您有 root 权限的话)。\r\n\r\n```bash\r\n# For ubuntu:\r\n$ sudo apt-get install liblzma-dev\r\n\r\n# For centos:\r\n$ yum install xz-devel\r\n```\r\n\r\n普通用户可以手动安装解决:\r\n\r\n```bash\r\n$ wget https://tukaani.org/xz/xz-5.2.5.tar.gz --no-check-certificat\r\n$ tar zvxf xz-5.2.5.tar.gz\r\n$ cd xz-5.2.5\r\n$ ./configure --prefix=/Bioinfo/Pipeline/SoftWare/xz-5.2.5\r\n$ make\r\n$ make install\r\n```\r\n\r\n最后,配置环境:\r\n\r\n```bash\r\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/xz-5.2.5/lib:$LD_LIBRARY_PATH\r\n```\r\n\r\n### _ctypes \r\n\r\n在 CentOS 6.x 安装 `libffi-devel`\xa0 的时候出现以下问题:\r\n\r\n```bash\r\n$ yum install libffi-devel\r\nLoaded plugins: product-id, refresh-packagekit, search-disabled-repos, security, subscription-manager\r\nThis system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.\r\nSetting up Install Process\r\ncdrom | 4.1 kB 00:00 ...\r\nNo package libffi-devel available.\r\nError: Nothing to do\r\n```\r\n\r\n可以使用下面的方法安装:\r\n```shell\r\n[root@log01 ~]# rpm -ivh http://mirror.centos.org/centos/6/os/x86_64/Packages/libffi-devel-3.0.5-3.2.el6.x86_64.rpm\r\nRetrieving http://mirror.centos.org/centos/6/os/x86_64/Packages/libffi-devel-3.0.5-3.2.el6.x86_64.rpm\r\nwarning: /var/tmp/rpm-tmp.V9ihbu: Header V3 RSA/SHA256 Signature, key ID c105b9de: NOKEY\r\nPreparing... ########################################### [100%]\r\n 1:libffi-devel ########################################### [100%]\r\n[root@log01 ~]# rpm -qa|grep libffi\r\nlibffi-3.0.5-3.2.el6.x86_64\r\nlibffi-devel-3.0.5-3.2.el6.x86_64\r\n```\r\n\r\n手动的源码方法安装如下:\r\n```bash\r\n$ wget ftp://sourceware.org/pub/libffi/libffi-3.2.1.tar.gz\r\n$ tar zvxf libffi-3.2.1.tar.gz\r\n$ ./configure --prefix=/Bioinfo/Pipeline/SoftWare/libffi-3.2.1\r\n$ make\r\n$ make install\r\n```\r\n\r\n### pygraphviz\r\n\r\n如果你不需要使用 pygraphviz,可以不用管这个依赖。\r\n\r\n> PyGraphviz is a Python interface to the Graphviz graph layout and visualization package. With PyGraphviz you can create, edit, read, write, and draw graphs using Python to access the Graphviz graph data structure and layout algorithms.\r\n\r\n> PyGraphviz 是 Graphviz 图形布局和可视化包的 Python 接口。 借助 PyGraphviz,您可以使用 Python 创建、编辑、读取、写入和绘制图形,以访问 Graphviz 图形数据结构和布局算法。\r\n\r\n```bash\r\n$ /Bioinfo/Pipeline/SoftWare/Python-3.7.3/bin/pip3 install pygraphviz\r\nCollecting pygraphviz\r\n Using cached https://files.pythonhosted.org/packages/7e/b1/d6d849ddaf6f11036f9980d433f383d4c13d1ebcfc3cd09bc845bda7e433/pygraphviz-1.5.zip\r\nInstalling collected packages: pygraphviz\r\n Running setup.py install for pygraphviz ... error\r\n Complete output from command /Bioinfo/Pipeline/SoftWare/Python-3.7.3/bin/python3.7 -u -c "import setuptools, tokenize;__file__=\'/tmp/pip-install-_zdjdg0j/pygraphviz/setup.py\';f=getattr(tokenize, \'open\', open)(__file__);code=f.read().replace(\'\\r\\n\', \'\\n\');f.close();exec(compile(code, __file__, \'exec\'))" install --record /tmp/pip-record-g0mz7lrq/install-record.txt --single-version-externally-managed --compile:\r\n running install\r\n Trying dpkg\r\n Failed to find dpkg\r\n Trying pkg-config\r\n Package libcgraph was not found in the pkg-config search path.\r\n Perhaps you should add the directory containing `libcgraph.pc\'\r\n to the PKG_CONFIG_PATH environment variable\r\n No package \'libcgraph\' found\r\n Traceback (most recent call last):\r\n File "", line 1, in \r\n File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup.py", line 93, in \r\n tests_require=[\'nose>=1.3.7\', \'doctest-ignore-unicode>=0.1.2\', \'mock>=2.0.0\'],\r\n File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/site-packages/setuptools/__init__.py", line 145, in setup\r\n return distutils.core.setup(**attrs)\r\n File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/distutils/core.py", line 148, in setup\r\n dist.run_commands()\r\n File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/distutils/dist.py", line 966, in run_commands\r\n self.run_command(cmd)\r\n File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/distutils/dist.py", line 985, in run_command\r\n cmd_obj.run()\r\n File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup_commands.py", line 44, in modified_run\r\n self.include_path, self.library_path = get_graphviz_dirs()\r\n File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup_extra.py", line 162, in get_graphviz_dirs\r\n include_dirs, library_dirs = _try_configure(include_dirs, library_dirs, _pkg_config)\r\n File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup_extra.py", line 117, in _try_configure\r\n i, l = try_function()\r\n File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup_extra.py", line 72, in _pkg_config\r\n output = S.check_output([\'pkg-config\', \'--libs-only-L\', \'libcgraph\'])\r\n File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/subprocess.py", line 395, in check_output\r\n **kwargs).stdout\r\n File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/subprocess.py", line 487, in run\r\n output=stdout, stderr=stderr)\r\n subprocess.CalledProcessError: Command \'[\'pkg-config\', \'--libs-only-L\', \'libcgraph\']\' returned non-zero exit status 1.\r\n\r\n ----------------------------------------\r\nCommand "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/bin/python3.7 -u -c "import setuptools, tokenize;__file__=\'/tmp/pip-install-_zdjdg0j/pygraphviz/setup.py\';f=getattr(tokenize, \'open\', open)(__file__);code=f.read().replace(\'\\r\\n\', \'\\n\');f.close();exec(compile(code, __file__, \'exec\'))" install --record /tmp/pip-record-g0mz7lrq/install-record.txt --single-version-externally-managed --compile" failed with error code 1 in /tmp/pip-install-_zdjdg0j/pygraphviz/\r\n\r\n```\r\n\r\n参考:《[Installation:fatal error: \'graphviz/cgraph.h\' file not found](https://github.com/pygraphviz/pygraphviz/issues/11)》\r\n\r\n```bash\r\n$ wget https://graphviz.gitlab.io/pub/graphviz/stable/SOURCES/graphviz.tar.gz\r\n$ tar zvxf graphviz.tar.gz\r\n$ cd graphviz-2.40.1\r\n$ ./configure --prefix=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1\r\n$ make && make install\r\n```\r\n\r\n推荐把安装好的 graphviz 添加到环境变量,这样可以避免运行过程中出现:**"pygraphviz/graphviz_wrap.c:2987:29: fatal error: graphviz/cgraph.h: No such file or directory"** 无法找到头文件的异常。\r\n\r\n```bash\r\nexport PKG_CONFIG_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib/pkgconfig:$PKG_CONFIG_PATH\r\nexport LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib:$LD_LIBRARY_PATH\r\nexport C_INCLUDE_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/include:$C_INCLUDE_PATH\r\nexport CPLUS_INCLUDE_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/include:$CPLUS_INCLUDE_PATH\r\n```\r\n\r\n如果 graphviz 添加到环境变量, `pygraphviz`\xa0的 python 包可以参考下面的方法安装:\r\n\r\n```bash\r\n$ /Bioinfo/Pipeline/SoftWare/Python-3.7.3/bin/pip3 install --global-option=build_ext --global-option="-I/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/include" --global-option="-L/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib" pygraphviz\r\n/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/site-packages/pip/_internal/commands/install.py:207: UserWarning: Disabling all use of wheels due to the use of --build-options / --global-options / --install-options.\r\n cmdoptions.check_install_build_global(options)\r\nCollecting pygraphviz\r\n Using cached https://files.pythonhosted.org/packages/7e/b1/d6d849ddaf6f11036f9980d433f383d4c13d1ebcfc3cd09bc845bda7e433/pygraphviz-1.5.zip\r\nInstalling collected packages: pygraphviz\r\n Running setup.py install for pygraphviz ... done\r\nSuccessfully installed pygraphviz-1.5\r\n```\r\n\r\n## 编译安装\r\n\r\n这里的编译安装,以 Python-3.11.6 为示例。\r\n\r\n第一,下载 Python 源码,解压。\r\n\r\n```bash\r\n# 官网下载地址 https://www.python.org/downloads\r\nwget https://www.python.org/ftp/python/3.11.6/Python-3.11.6.tgz\r\n\r\n# 解压到指定目录\r\ntar zvxf Python-3.11.6.tgz -C /usr/local/src\r\n```\r\n\r\n第二,进入解压的源码路径,编译 Python 源码。\r\n\r\n```bash\r\n$ export PKG_CONFIG_PATH=/Bioinfo/Pipeline/SoftWare/libffi-3.2.1/lib/pkgconfig:$PKG_CONFIG_PATH\r\n$ export PKG_CONFIG_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib/pkgconfig:$PKG_CONFIG_PATH\r\n\r\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/libffi-3.2.1/lib64:$LD_LIBRARY_PATH\r\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib:$LD_LIBRARY_PATH\r\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1/lib:$LD_LIBRARY_PATH\r\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/lib:$LD_LIBRARY_PATH\r\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/gdbm-1.23/lib:$LD_LIBRARY_PATH\r\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/lib:$LD_LIBRARY_PATH\r\n\r\n$ export TCLTK_LIBS="-L/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/lib -ltcl8.6 -ltk8.6"\r\n$ export TCLTK_CFLAGS="-I/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/include"\r\n\r\n$ ./configure \\\r\n--enable-optimizations \\\r\n--prefix=/Bioinfo/Pipeline/SoftWare/Python-3.11.6 \\\r\n--with-openssl=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1 \\\r\n--with-openssl-rpath=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1/lib \\\r\nCC=/Bioinfo/Pipeline/SoftWare/gcc-7.3.0/bin/gcc \\\r\nCXX=/Bioinfo/Pipeline/SoftWare/gcc-7.3.0/bin/c++ \\\r\nLDFLAGS="-L/Bioinfo/Pipeline/SoftWare/libffi-3.2.1/lib64 \\\r\n -L/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib \\\r\n -L/RiboBio/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/lib \\\r\n -L/Bioinfo/Pipeline/SoftWare/gdbm-1.23/lib" \\\r\nCPPFLAGS="-I/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/include \\\r\n -I/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/include \\\r\n -I/Bioinfo/Pipeline/SoftWare/gdbm-1.23/include" \\\r\nPKG_CONFIG_PATH="/Bioinfo/Pipeline/SoftWare/libffi-3.2.1/lib/pkgconfig: \\\r\n /Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib/pkgconfig"\r\n```\r\n\r\n- `--enable-optimizations`\xa0 是优化选项(LTO,PGO\xa0 等)加上这个 \xa0flag\xa0 编译后,性能有 \xa010%\xa0 左右的优化,但是这会明显的增加编译时间。建议使用这个参数;\r\n- `--prefix`\xa0 声明安装路径;\r\n- 安装多个 python 的版本,如果不开启`--enable-shared`,指定不同路径即可。当开启`--enable-shared` 时,默认只有一个版本的 python。\r\n- Python 3 编译可以在 configure 或者环境变量中指定 OpenSSL 安装路径进行编译的方式解决 OpenSSL 依赖,否则 `make`\xa0 过程可能出错。\r\n\r\n```shell\r\n$ make\r\n......\r\nThe following modules found by detect_modules() in setup.py, have been\r\nbuilt by the Makefile instead, as configured by the Setup files:\r\n_abc atexit pwd\r\ntime\r\n\r\n\r\nFailed to build these modules:\r\n_ctypes _hashlib _ssl\r\n\r\n\r\nCould not build the ssl module!\r\nPython requires an OpenSSL 1.0.2 or 1.1 compatible libssl with X509_VERIFY_PARAM_set1_host().\r\nLibreSSL 2.6.4 and earlier do not provide the necessary APIs, https://github.com/libressl-portable/portable/issues/381\r\n\r\n......\r\n```\r\n\r\n- `make`\xa0过程如果出现 `ModuleNotFoundError: No module named \'_ctypes\'`\xa0或者 `INFO: Could not locate ffi libs and/or headers`\xa0参考:\r\n\r\n![image.png](https://shub.weiyan.tech/yuque/elog-cookbook-img/FmK7bCeEeGjfbl1UVdvHyw3Jg8Zj.png)\r\n\r\n- 对于低版本的 Python 如果指定\xa0`--with-openssl=DIR`\xa0依然无法解决 ssl 模块的问题,可以参考修改 Modules/Setup.dist 文件(默认这块是注释的,放开注释即可。这块功能是开启 SSL 模块,不然会出现安装完毕后,提示找不到 ssl 模块的错误)再执行 configure,修改内容如下:\r\n\r\n```bash\r\n# Socket module helper for SSL support; you must comment out the other\r\n# socket line above, and possibly edit the SSL variable:\r\nSSL=/usr/local/ssl\r\n_ssl _ssl.c \\\r\n -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \\\r\n -L$(SSL)/lib -lssl -lcrypto\r\n```\r\n\r\n第三,Makefile 生后依次在当前路径执行编译和安装命令。\r\n\r\n```bash\r\nmake && make install\r\n```\r\n\r\n第四,安装完成。以上命令执行完毕,且无报错的情况下,我们将默认 python 换将切换至 3.11.6(一般不建议替换,个人建议把自定义安装的 Python bin 路径添加到 PATH 环境变量即可):\r\n\r\n```bash\r\n# 替换系统自带的 python(不建议)\r\nmv /usr/bin/python /usr/bin/python2\r\nln -s /Bioinfo/Pipeline/SoftWare/Python-3.11.6/bin/python3 /usr/bin/python3\r\n\r\n# 添加新 Python 到 PATH 环境变量(建议)\r\necho "export PATH=/Bioinfo/Pipeline/SoftWare/Python-3.11.6/bin:$PATH" >>~/.bashrc\r\nsource ~/.bashrc\r\n```\r\n\r\n运行命令 `python -V`\xa0,查看是否出现 3.11.6\xa0 的版本,出现即为安装成功。\r\n\r\n## 其他工具\r\n\r\nPython >= 3.10 在安装时候,默认会同时安装 **pip3**!如果你的 python < 3.10,可以参考下面的方法安装 pip。\r\n\r\n```bash\r\n# 下载 setuptools 和 pip 安装程序\r\ncurl https://bootstrap.pypa.io/get-pip.py -o get-pip.py\r\npython3 get-pip.py\r\n```\r\n\r\n至此,CentOS Linux release\xa06.5 下的 python-3.11.6\xa0 全部安装完成。如果在安装过程中出现其他的报错,建议把 error 关键信息直接复制到 Google 进行检索,参考其他人的解决方法。\r\n\r\n## 其他异常与解决\r\n\r\n### _bz2\r\n\r\n- 系统:CentOS Linux release 7.7.1908 (Core)\r\n- GCC:gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39)\r\n\r\n在 CentOS 7 中安装 Python-3.6.9 中发现 make 过程中一直提示:"**ModuleNotFoundError: No module named \'_bz2\'**",尽管 `sudo yum install bzip2 bzip2-devel`\xa0 已经安装了 bzip2 的依赖,问题还是不得其解。最后参考 stackoverflow 上的《Correctly building local python3, with bz2 support》,终于解决问题,下面记录一下。\r\n[Correctly building local python3, with bz2 support](https://stackoverflow.com/questions/51149227/correctly-building-local-python3-with-bz2-support)\r\n\r\n**手动安装 bzip2:**\r\n\r\n```bash\r\nwget https://nchc.dl.sourceforge.net/project/bzip2/bzip2-1.0.6.tar.gz\r\ntar zvxf bzip2-1.0.6.tar.gz\r\ncd bzip2-1.0.6\r\nmake -f Makefile_libbz2_so # 这一步是生成 libbz2.so.1.0.6 的动态库文件\r\nmake\r\nmake install PREFIX=/usr/local/software/bzip2-1.0.6\r\ncp libbz2.so.1.0.6 /usr/local/software/bzip2-1.0.6/lib/\r\n```\r\n\r\n**几点说明:**\r\n\r\n- bzip2 的官网 \xa0\xa0 已经把 bzip2 的源码下载链接放到了 \xa0SourceForge,网络上一些从 \xa0\xa0 下载的做法已经失效。\r\n- [SourceForge](https://sourceforge.net/projects/bzip2/files/) 上 bzip2 的最新版本还是 1.0.6(Last modified 2018-11-3),更高级版本的 bzip2 我也不知道是否存在,也不知道能不能用。\r\n\r\n![image.png](https://shub.weiyan.tech/yuque/elog-cookbook-img/FvgxGWlVJSxOCvgXFo9BPOa3ODm5.png)\r\n\r\n**编译安装 Python-3.6.9:**\r\n\r\n```bash\r\n$ wget https://www.python.org/ftp/python/3.6.9/Python-3.6.9.tgz\r\n$ tar zvxf Python-3.6.9.tgz\r\n$ cd Python-3.6.9\r\n$ ./configure --enable-optimizations --prefix=/usr/local/software/python-3.6 CFLAGS="-I/usr/local/software/bzip2-1.0.6/include" LDFLAGS="-L/usr/local/software/bzip2-1.0.6/lib"\r\n$ make\r\n$ make install\r\n```\r\n\r\n- Python-3.6.9 中的 `./configure --help`\xa0中没有 `--with-openssl`\xa0参数!有点神奇,我也不知道原因。\r\n- 安装完成可以用 `from _bz2 import BZ2Compressor, BZ2Decompressor`\xa0测试一下 `_bz2`\xa0 是否可用。\r\n\r\n\r\n## 参考资料\r\n\r\n1. 行者无疆-ITer,《[python2.7 源码编译安装](https://www.cnblogs.com/ITer-jack/p/8305912.html)》, 博客园\r\n2. Scott Frazer,《[How do I compile Python 3.4 with custom OpenSSL?](https://stackoverflow.com/questions/23548188/how-do-i-compile-python-3-4-with-custom-openssl)》, Stack Overflow\r\n', 'bodyText': '编程,作为生物信息学的一个基础性技能,是任何一个生信工程师都无法绕开话题。也许有些人还在纠结 Perl 和 Python 到底应该学习哪一个,但作为目前最火最流行的编程语言 Python 还是非常值得尝试的。它不但可以进行文本处理,在统计、网站、游戏、爬虫、数据可视化等方面也有非常强大的应用,比起曾经的 Perl 真的强大和全面很多,且比 Perl 更容易入手。不管从长远发展,还是短期需要,学会 Python,看懂 Perl (或者先学 \xa0 Python,后学 Perl) 应该是每一个生信工程必备的基础技能之一。\n工欲善其事,必先利其器。关于 Python 安装教程在网上一搜一大把,但总感觉不够全面,尤其对于中间出现的一些问题的解决方法不尽如人意。鉴于此,本文基于 \xa0CentOS/RHEL Linux 对 Python 的源码编译安装进行了一下简单的总结,记录如下。\n安装环境\nRed Hat 6.5 + GCC 4.4.7(GCC-7.3.0 - 此版本 gcc 为手动安装)。\nGCC 高级版本手动或者 yum 安装参考以下文章:\n\nSCL+Devtoolset 安装与使用笔记 · 语雀\n非 root 用户手动编译安装 GCC · 语雀\n\n$ lsb_release -a\nLSB Version: :base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noarch:graphics-4.0-amd64:graphics-4.0-noarch:printing-4.0-amd64:printing-4.0-noarch\nDistributor ID: RedHatEnterpriseServer\nDescription: Red Hat Enterprise Linux Server release 6.5 (Santiago)\nRelease: 6.5\nCodename: Santiago\n\n$ gcc --version\ngcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-4)\nCopyright (C) 2010 Free Software Foundation, Inc.\nThis is free software; see the source for copying conditions. There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n解决依赖\n如果您拥有 root 权限,请执以下依赖安装:\nyum install zlib\nyum install zlib-devel\nyum install openssl\nyum install openssl-devel\nyum install libffi\nyum install libffi-devel\nyum install readline readline-devel sqlite sqlite-devel tk-devel\n\n\n\n缺少库名称\n安装命令\n\n\n\n\n_uuid\nyum install libuuid-devel\n\n\nreadline\nyum install readline-devel\n\n\n_tkinter\nyum install tk-devel\n\n\n_ffi\nyum install libffi-devel\n\n\n_curses\nyum install ncurses-libs\n\n\n_sqlite\nyum install sqlite-devel\n\n\n_bz2\nyum isntall bzip2-devel\n\n\n_ssl\nyum install openssl-devel\n\n\n_gdbm\nyum install gdbm-devel\n\n\n_dbi\nyum install libdbi-devel\n\n\n_zlib\nyum install zlib-devel\n\n\nlzma\nyum install xz-develyum install python-backports-lzma\n\n\n\n如果您没有 root 权限,可以参考《手把手教你在 Linux 源码安装最新版本的 R》一文,手动一个个去解决以上的依赖。\n_sqlite3\n执行 make 过程中提示 _sqlite3 not found,如下:\n$ make\n......\nPython build finished successfully!\nThe necessary bits to build these optional modules were not found:\n_sqlite3 _ssl\nTo find the necessary bits, look in setup.py in detect_modules() for the module\'s name.\n\nThe following modules found by detect_modules() in setup.py, have been\nbuilt by the Makefile instead, as configured by the Setup files:\n_abc atexit pwd\ntime\n系统已安装 sqlite3\n如果执行 rpm -qa|grep sqlite 看到 sqlite 和 sqlite-devel 都已经安装(libsqlite3.so 默认保存在 /usr/lib64 下; sqlite3.h 默认保存在 /usr/include 下)。\n$ sqlite3 -version\n3.6.20\n\n$ ll /usr/lib64/libsqlite3.so\nlrwxrwxrwx 1 root root 19 Apr 23 2015 /usr/lib64/libsqlite3.so -> libsqlite3.so.0.8.6\n\n$ ll /usr/include/sqlite3.h\n-rw-r--r-- 1 root root 263K Nov 25 2009 /usr/include/sqlite3.h\n但是,执行 make 依然出现以上报错,参考下面的方法《python build from source: cannot build optional module sqlite3 - Stack Overflow》。\n手动安装 sqlite3\n$ wget https://www.sqlite.org/2021/sqlite-autoconf-3360000.tar.gz --no-check-certificate\n$ tar zvxf sqlite-autoconf-3360000.tar.gz\n$ cd sqlite-autoconf-3360000\n$ ./configure --prefix=/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0\n$ make\n$ make install\n配置 sqlite3\n\n配置环境\n\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/lib:$LD_LIBRARY_PATH\n\n调整源码或编译\n\n对于 3.11.x 以上版本的 Python 可以在 configure 指定自定义安装的 sqlite3 路径解决 _sqlite3 依赖。\n./configure ... \\\n LDFLAGS="-L/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/lib" \\\n CPPFLAGS="-I/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/include" \n\n有些低版本的 Python (如 3.7) 可能需要再源码文件中加入 sqlite3.h 的文件路径。\n\n找到 sqlite3.h 文件的保存目录。\n修改 setup.py 文件,在 sqlite_inc_paths 中加上 sqlite3.h 的文件路径。\n\nsqlite_inc_paths = [ \'/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/include\',\n \'/usr/include\',\n \'/usr/include/sqlite\',\n \'/usr/include/sqlite3\',\n \'/usr/local/include\',\n \'/usr/local/include/sqlite\',\n \'/usr/local/include/sqlite3\',\n ]\n_ssl\nPython3 需要引用 openssl\xa0 模块,但是 python3.7+ 在 CentOS 中要求的 openssl 版本最低为 1.0.2,而 CentOS 默认的为 1.0.1(CentOS-6.x 通过 yum\xa0 源安装的 openssl 的最高版本是 1.0.1),所以需要手动更新 openssl。\n对于 openssl 版本的选择,建议至少选择 1.1.1+ 版本:\n\nurllib3 v2.0 only supports OpenSSL 1.1.1+, currently the \'ssl\' module is compiled with \'OpenSSL 1.0.2k-fips 26 Jan 2017\'. See: urllib3/urllib3#2168\nPython requires an OpenSSL 1.0.2 or 1.1 compatible libssl with X509_VERIFY_PARAM_set1_host().\n\n# 下载\nwget http://www.openssl.org/source/openssl-1.1.1.tar.gz\n\n# 解压缩\ntar -zxvf openssl-1.1.1.tar.gz\n\n# 进入目录安装\ncd openssl-1.1.1\n\n# 进行配置下,自定义\n./config --prefix=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1 shared zlib\n\n# 编译并安装\nmake && make install\n\n# 配置到用户环境变量,随处使用\necho "export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1/lib:$LD_LIBRARY_PATH" >> $HOME/.bashrc\n\n# 是环境变量配置生效\nsource $HOME/.bashrc\n请注意:\n\nopenssl\xa0编译(config)的时候 必须要加上 shared\xa0 参数,否者源码安装 Python 即使添加了 --with-openssl\xa0的自定义路径,依然会导致 Could not build the ssl module!\xa0报错!\n从 https://www.openssl.org/source/\xa0下载的源码 openssl-1.0.2s、openssl-1.0.2m,包括 \xa0CentOS-7.5 使用 yum\xa0安装的最高版本的 openssl-1.0.2k 目前发现依然会导致 Could not build the ssl module\xa0,建议从 https://www.openssl.org/source/old/\xa0下载 1.1.1 的源码编译安装。\n\n最后,在 Python 执行 configure 的时候指定 openssl 的相关参数:\n./configure ... \\\n --with-openssl=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1 \\\n --with-openssl-rpath=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1/lib \\\n\n_tkinter\nTkinter 模块缺失是一个比较棘手的问题,为此专门写了一篇文章来介绍这个问题。\n具体请参考:Python 中 tkinter 源码安装使用与中文乱码 - Knowledge-Garden#12\n_dbm\n_dbm 和 _gdbm 的模块缺失可以通过下面手动的方法解决。\nwget https://ftp.gnu.org/gnu/gdbm/gdbm-1.23.tar.gz\ntar -zxvf gdbm-1.23.tar.gz\n./configure --prefix=/Bioinfo/Pipeline/SoftWare/gdbm-1.23 --enable-libgdbm-compat --enable-debug\nmake && make install\n\n最后,增加环境变量,并调整 Python 执行 configure 时的参数:\nexport PATH=/Bioinfo/Pipeline/SoftWare/gdbm-1.23/bin:$PATH\nexport LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/gdbm-1.23/lib:$LD_LIBRARY_PATH\n\n./configure ... \\\n LDFLAGS="-L/Bioinfo/Pipeline/SoftWare/gdbm-1.23/lib" \\\n CPPFLAGS="-I/Bioinfo/Pipeline/SoftWare/gdbm-1.23/include"\n\n_lzma\n正常情况下,下面的方法可以解决该问题(如果您有 root 权限的话)。\n# For ubuntu:\n$ sudo apt-get install liblzma-dev\n\n# For centos:\n$ yum install xz-devel\n普通用户可以手动安装解决:\n$ wget https://tukaani.org/xz/xz-5.2.5.tar.gz --no-check-certificat\n$ tar zvxf xz-5.2.5.tar.gz\n$ cd xz-5.2.5\n$ ./configure --prefix=/Bioinfo/Pipeline/SoftWare/xz-5.2.5\n$ make\n$ make install\n最后,配置环境:\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/xz-5.2.5/lib:$LD_LIBRARY_PATH\n_ctypes\n在 CentOS 6.x 安装 libffi-devel\xa0 的时候出现以下问题:\n$ yum install libffi-devel\nLoaded plugins: product-id, refresh-packagekit, search-disabled-repos, security, subscription-manager\nThis system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.\nSetting up Install Process\ncdrom | 4.1 kB 00:00 ...\nNo package libffi-devel available.\nError: Nothing to do\n可以使用下面的方法安装:\n[root@log01 ~]# rpm -ivh http://mirror.centos.org/centos/6/os/x86_64/Packages/libffi-devel-3.0.5-3.2.el6.x86_64.rpm\nRetrieving http://mirror.centos.org/centos/6/os/x86_64/Packages/libffi-devel-3.0.5-3.2.el6.x86_64.rpm\nwarning: /var/tmp/rpm-tmp.V9ihbu: Header V3 RSA/SHA256 Signature, key ID c105b9de: NOKEY\nPreparing... ########################################### [100%]\n 1:libffi-devel ########################################### [100%]\n[root@log01 ~]# rpm -qa|grep libffi\nlibffi-3.0.5-3.2.el6.x86_64\nlibffi-devel-3.0.5-3.2.el6.x86_64\n手动的源码方法安装如下:\n$ wget ftp://sourceware.org/pub/libffi/libffi-3.2.1.tar.gz\n$ tar zvxf libffi-3.2.1.tar.gz\n$ ./configure --prefix=/Bioinfo/Pipeline/SoftWare/libffi-3.2.1\n$ make\n$ make install\npygraphviz\n如果你不需要使用 pygraphviz,可以不用管这个依赖。\n\nPyGraphviz is a Python interface to the Graphviz graph layout and visualization package. With PyGraphviz you can create, edit, read, write, and draw graphs using Python to access the Graphviz graph data structure and layout algorithms.\n\n\nPyGraphviz 是 Graphviz 图形布局和可视化包的 Python 接口。 借助 PyGraphviz,您可以使用 Python 创建、编辑、读取、写入和绘制图形,以访问 Graphviz 图形数据结构和布局算法。\n\n$ /Bioinfo/Pipeline/SoftWare/Python-3.7.3/bin/pip3 install pygraphviz\nCollecting pygraphviz\n Using cached https://files.pythonhosted.org/packages/7e/b1/d6d849ddaf6f11036f9980d433f383d4c13d1ebcfc3cd09bc845bda7e433/pygraphviz-1.5.zip\nInstalling collected packages: pygraphviz\n Running setup.py install for pygraphviz ... error\n Complete output from command /Bioinfo/Pipeline/SoftWare/Python-3.7.3/bin/python3.7 -u -c "import setuptools, tokenize;__file__=\'/tmp/pip-install-_zdjdg0j/pygraphviz/setup.py\';f=getattr(tokenize, \'open\', open)(__file__);code=f.read().replace(\'\\r\\n\', \'\\n\');f.close();exec(compile(code, __file__, \'exec\'))" install --record /tmp/pip-record-g0mz7lrq/install-record.txt --single-version-externally-managed --compile:\n running install\n Trying dpkg\n Failed to find dpkg\n Trying pkg-config\n Package libcgraph was not found in the pkg-config search path.\n Perhaps you should add the directory containing `libcgraph.pc\'\n to the PKG_CONFIG_PATH environment variable\n No package \'libcgraph\' found\n Traceback (most recent call last):\n File "", line 1, in \n File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup.py", line 93, in \n tests_require=[\'nose>=1.3.7\', \'doctest-ignore-unicode>=0.1.2\', \'mock>=2.0.0\'],\n File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/site-packages/setuptools/__init__.py", line 145, in setup\n return distutils.core.setup(**attrs)\n File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/distutils/core.py", line 148, in setup\n dist.run_commands()\n File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/distutils/dist.py", line 966, in run_commands\n self.run_command(cmd)\n File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/distutils/dist.py", line 985, in run_command\n cmd_obj.run()\n File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup_commands.py", line 44, in modified_run\n self.include_path, self.library_path = get_graphviz_dirs()\n File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup_extra.py", line 162, in get_graphviz_dirs\n include_dirs, library_dirs = _try_configure(include_dirs, library_dirs, _pkg_config)\n File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup_extra.py", line 117, in _try_configure\n i, l = try_function()\n File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup_extra.py", line 72, in _pkg_config\n output = S.check_output([\'pkg-config\', \'--libs-only-L\', \'libcgraph\'])\n File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/subprocess.py", line 395, in check_output\n **kwargs).stdout\n File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/subprocess.py", line 487, in run\n output=stdout, stderr=stderr)\n subprocess.CalledProcessError: Command \'[\'pkg-config\', \'--libs-only-L\', \'libcgraph\']\' returned non-zero exit status 1.\n\n ----------------------------------------\nCommand "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/bin/python3.7 -u -c "import setuptools, tokenize;__file__=\'/tmp/pip-install-_zdjdg0j/pygraphviz/setup.py\';f=getattr(tokenize, \'open\', open)(__file__);code=f.read().replace(\'\\r\\n\', \'\\n\');f.close();exec(compile(code, __file__, \'exec\'))" install --record /tmp/pip-record-g0mz7lrq/install-record.txt --single-version-externally-managed --compile" failed with error code 1 in /tmp/pip-install-_zdjdg0j/pygraphviz/\n\n参考:《Installation:fatal error: \'graphviz/cgraph.h\' file not found》\n$ wget https://graphviz.gitlab.io/pub/graphviz/stable/SOURCES/graphviz.tar.gz\n$ tar zvxf graphviz.tar.gz\n$ cd graphviz-2.40.1\n$ ./configure --prefix=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1\n$ make && make install\n推荐把安装好的 graphviz 添加到环境变量,这样可以避免运行过程中出现:"pygraphviz/graphviz_wrap.c:2987:29: fatal error: graphviz/cgraph.h: No such file or directory" 无法找到头文件的异常。\nexport PKG_CONFIG_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib/pkgconfig:$PKG_CONFIG_PATH\nexport LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib:$LD_LIBRARY_PATH\nexport C_INCLUDE_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/include:$C_INCLUDE_PATH\nexport CPLUS_INCLUDE_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/include:$CPLUS_INCLUDE_PATH\n如果 graphviz 添加到环境变量, pygraphviz\xa0的 python 包可以参考下面的方法安装:\n$ /Bioinfo/Pipeline/SoftWare/Python-3.7.3/bin/pip3 install --global-option=build_ext --global-option="-I/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/include" --global-option="-L/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib" pygraphviz\n/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/site-packages/pip/_internal/commands/install.py:207: UserWarning: Disabling all use of wheels due to the use of --build-options / --global-options / --install-options.\n cmdoptions.check_install_build_global(options)\nCollecting pygraphviz\n Using cached https://files.pythonhosted.org/packages/7e/b1/d6d849ddaf6f11036f9980d433f383d4c13d1ebcfc3cd09bc845bda7e433/pygraphviz-1.5.zip\nInstalling collected packages: pygraphviz\n Running setup.py install for pygraphviz ... done\nSuccessfully installed pygraphviz-1.5\n编译安装\n这里的编译安装,以 Python-3.11.6 为示例。\n第一,下载 Python 源码,解压。\n# 官网下载地址 https://www.python.org/downloads\nwget https://www.python.org/ftp/python/3.11.6/Python-3.11.6.tgz\n\n# 解压到指定目录\ntar zvxf Python-3.11.6.tgz -C /usr/local/src\n第二,进入解压的源码路径,编译 Python 源码。\n$ export PKG_CONFIG_PATH=/Bioinfo/Pipeline/SoftWare/libffi-3.2.1/lib/pkgconfig:$PKG_CONFIG_PATH\n$ export PKG_CONFIG_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib/pkgconfig:$PKG_CONFIG_PATH\n\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/libffi-3.2.1/lib64:$LD_LIBRARY_PATH\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib:$LD_LIBRARY_PATH\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1/lib:$LD_LIBRARY_PATH\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/lib:$LD_LIBRARY_PATH\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/gdbm-1.23/lib:$LD_LIBRARY_PATH\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/lib:$LD_LIBRARY_PATH\n\n$ export TCLTK_LIBS="-L/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/lib -ltcl8.6 -ltk8.6"\n$ export TCLTK_CFLAGS="-I/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/include"\n\n$ ./configure \\\n--enable-optimizations \\\n--prefix=/Bioinfo/Pipeline/SoftWare/Python-3.11.6 \\\n--with-openssl=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1 \\\n--with-openssl-rpath=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1/lib \\\nCC=/Bioinfo/Pipeline/SoftWare/gcc-7.3.0/bin/gcc \\\nCXX=/Bioinfo/Pipeline/SoftWare/gcc-7.3.0/bin/c++ \\\nLDFLAGS="-L/Bioinfo/Pipeline/SoftWare/libffi-3.2.1/lib64 \\\n -L/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib \\\n -L/RiboBio/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/lib \\\n -L/Bioinfo/Pipeline/SoftWare/gdbm-1.23/lib" \\\nCPPFLAGS="-I/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/include \\\n -I/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/include \\\n -I/Bioinfo/Pipeline/SoftWare/gdbm-1.23/include" \\\nPKG_CONFIG_PATH="/Bioinfo/Pipeline/SoftWare/libffi-3.2.1/lib/pkgconfig: \\\n /Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib/pkgconfig"\n\n--enable-optimizations\xa0 是优化选项(LTO,PGO\xa0 等)加上这个 \xa0flag\xa0 编译后,性能有 \xa010%\xa0 左右的优化,但是这会明显的增加编译时间。建议使用这个参数;\n--prefix\xa0 声明安装路径;\n安装多个 python 的版本,如果不开启--enable-shared,指定不同路径即可。当开启--enable-shared 时,默认只有一个版本的 python。\nPython 3 编译可以在 configure 或者环境变量中指定 OpenSSL 安装路径进行编译的方式解决 OpenSSL 依赖,否则 make\xa0 过程可能出错。\n\n$ make\n......\nThe following modules found by detect_modules() in setup.py, have been\nbuilt by the Makefile instead, as configured by the Setup files:\n_abc atexit pwd\ntime\n\n\nFailed to build these modules:\n_ctypes _hashlib _ssl\n\n\nCould not build the ssl module!\nPython requires an OpenSSL 1.0.2 or 1.1 compatible libssl with X509_VERIFY_PARAM_set1_host().\nLibreSSL 2.6.4 and earlier do not provide the necessary APIs, https://github.com/libressl-portable/portable/issues/381\n\n......\n\nmake\xa0过程如果出现 ModuleNotFoundError: No module named \'_ctypes\'\xa0或者 INFO: Could not locate ffi libs and/or headers\xa0参考:https://groups.google.com/forum/#!topic/comp.lang.python/npv-wzmytzo\n\n\n\n对于低版本的 Python 如果指定\xa0--with-openssl=DIR\xa0依然无法解决 ssl 模块的问题,可以参考修改 Modules/Setup.dist 文件(默认这块是注释的,放开注释即可。这块功能是开启 SSL 模块,不然会出现安装完毕后,提示找不到 ssl 模块的错误)再执行 configure,修改内容如下:\n\n# Socket module helper for SSL support; you must comment out the other\n# socket line above, and possibly edit the SSL variable:\nSSL=/usr/local/ssl\n_ssl _ssl.c \\\n -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \\\n -L$(SSL)/lib -lssl -lcrypto\n第三,Makefile 生后依次在当前路径执行编译和安装命令。\nmake && make install\n第四,安装完成。以上命令执行完毕,且无报错的情况下,我们将默认 python 换将切换至 3.11.6(一般不建议替换,个人建议把自定义安装的 Python bin 路径添加到 PATH 环境变量即可):\n# 替换系统自带的 python(不建议)\nmv /usr/bin/python /usr/bin/python2\nln -s /Bioinfo/Pipeline/SoftWare/Python-3.11.6/bin/python3 /usr/bin/python3\n\n# 添加新 Python 到 PATH 环境变量(建议)\necho "export PATH=/Bioinfo/Pipeline/SoftWare/Python-3.11.6/bin:$PATH" >>~/.bashrc\nsource ~/.bashrc\n运行命令 python -V\xa0,查看是否出现 3.11.6\xa0 的版本,出现即为安装成功。\n其他工具\nPython >= 3.10 在安装时候,默认会同时安装 pip3!如果你的 python < 3.10,可以参考下面的方法安装 pip。\n# 下载 setuptools 和 pip 安装程序\ncurl https://bootstrap.pypa.io/get-pip.py -o get-pip.py\npython3 get-pip.py\n至此,CentOS Linux release\xa06.5 下的 python-3.11.6\xa0 全部安装完成。如果在安装过程中出现其他的报错,建议把 error 关键信息直接复制到 Google 进行检索,参考其他人的解决方法。\n其他异常与解决\n_bz2\n\n系统:CentOS Linux release 7.7.1908 (Core)\nGCC:gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39)\n\n在 CentOS 7 中安装 Python-3.6.9 中发现 make 过程中一直提示:"ModuleNotFoundError: No module named \'_bz2\'",尽管 sudo yum install bzip2 bzip2-devel\xa0 已经安装了 bzip2 的依赖,问题还是不得其解。最后参考 stackoverflow 上的《Correctly building local python3, with bz2 support》,终于解决问题,下面记录一下。\nCorrectly building local python3, with bz2 support\n手动安装 bzip2:\nwget https://nchc.dl.sourceforge.net/project/bzip2/bzip2-1.0.6.tar.gz\ntar zvxf bzip2-1.0.6.tar.gz\ncd bzip2-1.0.6\nmake -f Makefile_libbz2_so # 这一步是生成 libbz2.so.1.0.6 的动态库文件\nmake\nmake install PREFIX=/usr/local/software/bzip2-1.0.6\ncp libbz2.so.1.0.6 /usr/local/software/bzip2-1.0.6/lib/\n几点说明:\n\nbzip2 的官网 \xa0http://www.bzip.org/\xa0 已经把 bzip2 的源码下载链接放到了 \xa0SourceForge,网络上一些从 \xa0http://www.bzip.org/1.0.6/bzip2-1.0.6.tar.gz\xa0 下载的做法已经失效。\nSourceForge 上 bzip2 的最新版本还是 1.0.6(Last modified 2018-11-3),更高级版本的 bzip2 我也不知道是否存在,也不知道能不能用。\n\n\n编译安装 Python-3.6.9:\n$ wget https://www.python.org/ftp/python/3.6.9/Python-3.6.9.tgz\n$ tar zvxf Python-3.6.9.tgz\n$ cd Python-3.6.9\n$ ./configure --enable-optimizations --prefix=/usr/local/software/python-3.6 CFLAGS="-I/usr/local/software/bzip2-1.0.6/include" LDFLAGS="-L/usr/local/software/bzip2-1.0.6/lib"\n$ make\n$ make install\n\nPython-3.6.9 中的 ./configure --help\xa0中没有 --with-openssl\xa0参数!有点神奇,我也不知道原因。\n安装完成可以用 from _bz2 import BZ2Compressor, BZ2Decompressor\xa0测试一下 _bz2\xa0 是否可用。\n\n参考资料\n\n行者无疆-ITer,《python2.7 源码编译安装》, 博客园\nScott Frazer,《How do I compile Python 3.4 with custom OpenSSL?》, Stack Overflow', 'bodyHTML': '

编程,作为生物信息学的一个基础性技能,是任何一个生信工程师都无法绕开话题。也许有些人还在纠结 Perl 和 Python 到底应该学习哪一个,但作为目前最火最流行的编程语言 Python 还是非常值得尝试的。它不但可以进行文本处理,在统计、网站、游戏、爬虫、数据可视化等方面也有非常强大的应用,比起曾经的 Perl 真的强大和全面很多,且比 Perl 更容易入手。不管从长远发展,还是短期需要,学会 Python,看懂 Perl (或者先学 \xa0 Python,后学 Perl) 应该是每一个生信工程必备的基础技能之一。

\n

工欲善其事,必先利其器。关于 Python 安装教程在网上一搜一大把,但总感觉不够全面,尤其对于中间出现的一些问题的解决方法不尽如人意。鉴于此,本文基于 \xa0CentOS/RHEL Linux 对 Python 的源码编译安装进行了一下简单的总结,记录如下。

\n

安装环境

\n

Red Hat 6.5 + GCC 4.4.7(GCC-7.3.0 - 此版本 gcc 为手动安装)。

\n

GCC 高级版本手动或者 yum 安装参考以下文章:

\n\n
$ lsb_release -a\nLSB Version:    :base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noarch:graphics-4.0-amd64:graphics-4.0-noarch:printing-4.0-amd64:printing-4.0-noarch\nDistributor ID: RedHatEnterpriseServer\nDescription:    Red Hat Enterprise Linux Server release 6.5 (Santiago)\nRelease:        6.5\nCodename:       Santiago\n\n$ gcc --version\ngcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-4)\nCopyright (C) 2010 Free Software Foundation, Inc.\nThis is free software; see the source for copying conditions.  There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
\n

解决依赖

\n

如果您拥有 root 权限,请执以下依赖安装:

\n
yum install zlib\nyum install zlib-devel\nyum install openssl\nyum install openssl-devel\nyum install libffi\nyum install libffi-devel\nyum install readline readline-devel sqlite sqlite-devel tk-devel
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
缺少库名称安装命令
_uuidyum install libuuid-devel
readlineyum install readline-devel
_tkinteryum install tk-devel
_ffiyum install libffi-devel
_cursesyum install ncurses-libs
_sqliteyum install sqlite-devel
_bz2yum isntall bzip2-devel
_sslyum install openssl-devel
_gdbmyum install gdbm-devel
_dbiyum install libdbi-devel
_zlibyum install zlib-devel
lzmayum install xz-develyum install python-backports-lzma
\n

如果您没有 root 权限,可以参考《手把手教你在 Linux 源码安装最新版本的 R》一文,手动一个个去解决以上的依赖。

\n

_sqlite3

\n

执行 make 过程中提示 _sqlite3 not found,如下:

\n
$ make\n......\nPython build finished successfully!\nThe necessary bits to build these optional modules were not found:\n_sqlite3              _ssl\nTo find the necessary bits, look in setup.py in detect_modules() for the module\'s name.\n\nThe following modules found by detect_modules() in setup.py, have been\nbuilt by the Makefile instead, as configured by the Setup files:\n_abc                  atexit                pwd\ntime
\n

系统已安装 sqlite3

\n

如果执行 rpm -qa|grep sqlite 看到 sqlite 和 sqlite-devel 都已经安装(libsqlite3.so 默认保存在 /usr/lib64 下; sqlite3.h 默认保存在 /usr/include 下)。

\n
$ sqlite3 -version\n3.6.20\n\n$ ll /usr/lib64/libsqlite3.so\nlrwxrwxrwx 1 root root 19 Apr 23  2015 /usr/lib64/libsqlite3.so -> libsqlite3.so.0.8.6\n\n$ ll /usr/include/sqlite3.h\n-rw-r--r-- 1 root root 263K Nov 25  2009 /usr/include/sqlite3.h
\n

但是,执行 make 依然出现以上报错,参考下面的方法《python build from source: cannot build optional module sqlite3 - Stack Overflow》。

\n

手动安装 sqlite3

\n
$ wget https://www.sqlite.org/2021/sqlite-autoconf-3360000.tar.gz --no-check-certificate\n$ tar zvxf sqlite-autoconf-3360000.tar.gz\n$ cd sqlite-autoconf-3360000\n$ ./configure --prefix=/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0\n$ make\n$ make install
\n

配置 sqlite3

\n
    \n
  1. 配置环境
  2. \n
\n
$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/lib:$LD_LIBRARY_PATH
\n
    \n
  1. 调整源码或编译
  2. \n
\n

对于 3.11.x 以上版本的 Python 可以在 configure 指定自定义安装的 sqlite3 路径解决 _sqlite3 依赖。

\n
./configure ... \\\n    LDFLAGS="-L/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/lib" \\\n    CPPFLAGS="-I/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/include" \n
\n

有些低版本的 Python (如 3.7) 可能需要再源码文件中加入 sqlite3.h 的文件路径。

\n
    \n
  1. 找到 sqlite3.h 文件的保存目录。
  2. \n
  3. 修改 setup.py 文件,在 sqlite_inc_paths 中加上 sqlite3.h 的文件路径。
  4. \n
\n
sqlite_inc_paths = [ \'/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/include\',\n                     \'/usr/include\',\n                     \'/usr/include/sqlite\',\n                     \'/usr/include/sqlite3\',\n                     \'/usr/local/include\',\n                     \'/usr/local/include/sqlite\',\n                     \'/usr/local/include/sqlite3\',\n                   ]
\n

_ssl

\n

Python3 需要引用 openssl\xa0 模块,但是 python3.7+ 在 CentOS 中要求的 openssl 版本最低为 1.0.2,而 CentOS 默认的为 1.0.1(CentOS-6.x 通过 yum\xa0 源安装的 openssl 的最高版本是 1.0.1),所以需要手动更新 openssl。

\n

对于 openssl 版本的选择,建议至少选择 1.1.1+ 版本:

\n
    \n
  1. urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the \'ssl\' module is compiled with \'OpenSSL 1.0.2k-fips 26 Jan 2017\'. See: urllib3/urllib3#2168
  2. \n
  3. Python requires an OpenSSL 1.0.2 or 1.1 compatible libssl with X509_VERIFY_PARAM_set1_host().
  4. \n
\n
# 下载\nwget http://www.openssl.org/source/openssl-1.1.1.tar.gz\n\n# 解压缩\ntar -zxvf openssl-1.1.1.tar.gz\n\n# 进入目录安装\ncd openssl-1.1.1\n\n# 进行配置下,自定义\n./config --prefix=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1 shared zlib\n\n# 编译并安装\nmake && make install\n\n# 配置到用户环境变量,随处使用\necho "export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1/lib:$LD_LIBRARY_PATH" >> $HOME/.bashrc\n\n# 是环境变量配置生效\nsource $HOME/.bashrc
\n

请注意:

\n
    \n
  1. openssl\xa0编译(config)的时候 必须要加上 shared\xa0 参数,否者源码安装 Python 即使添加了 --with-openssl\xa0的自定义路径,依然会导致 Could not build the ssl module!\xa0报错!
  2. \n
  3. https://www.openssl.org/source/\xa0下载的源码 openssl-1.0.2s、openssl-1.0.2m,包括 \xa0CentOS-7.5 使用 yum\xa0安装的最高版本的 openssl-1.0.2k 目前发现依然会导致 Could not build the ssl module\xa0,建议从 https://www.openssl.org/source/old/\xa0下载 1.1.1 的源码编译安装。
  4. \n
\n

最后,在 Python 执行 configure 的时候指定 openssl 的相关参数:

\n
./configure ... \\\n    --with-openssl=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1 \\\n    --with-openssl-rpath=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1/lib \\\n
\n

_tkinter

\n

Tkinter 模块缺失是一个比较棘手的问题,为此专门写了一篇文章来介绍这个问题。

\n

具体请参考:Python 中 tkinter 源码安装使用与中文乱码 - Knowledge-Garden#12

\n

_dbm

\n

_dbm_gdbm 的模块缺失可以通过下面手动的方法解决。

\n
wget https://ftp.gnu.org/gnu/gdbm/gdbm-1.23.tar.gz\ntar -zxvf gdbm-1.23.tar.gz\n./configure --prefix=/Bioinfo/Pipeline/SoftWare/gdbm-1.23 --enable-libgdbm-compat  --enable-debug\nmake && make install\n
\n

最后,增加环境变量,并调整 Python 执行 configure 时的参数:

\n
export PATH=/Bioinfo/Pipeline/SoftWare/gdbm-1.23/bin:$PATH\nexport LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/gdbm-1.23/lib:$LD_LIBRARY_PATH\n\n./configure ... \\\n    LDFLAGS="-L/Bioinfo/Pipeline/SoftWare/gdbm-1.23/lib" \\\n    CPPFLAGS="-I/Bioinfo/Pipeline/SoftWare/gdbm-1.23/include"\n
\n

_lzma

\n

正常情况下,下面的方法可以解决该问题(如果您有 root 权限的话)。

\n
# For ubuntu:\n$ sudo apt-get install liblzma-dev\n\n# For centos:\n$ yum install xz-devel
\n

普通用户可以手动安装解决:

\n
$ wget https://tukaani.org/xz/xz-5.2.5.tar.gz --no-check-certificat\n$ tar zvxf xz-5.2.5.tar.gz\n$ cd xz-5.2.5\n$ ./configure --prefix=/Bioinfo/Pipeline/SoftWare/xz-5.2.5\n$ make\n$ make install
\n

最后,配置环境:

\n
$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/xz-5.2.5/lib:$LD_LIBRARY_PATH
\n

_ctypes

\n

在 CentOS 6.x 安装 libffi-devel\xa0 的时候出现以下问题:

\n
$ yum install libffi-devel\nLoaded plugins: product-id, refresh-packagekit, search-disabled-repos, security, subscription-manager\nThis system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.\nSetting up Install Process\ncdrom                                                                                                                                         | 4.1 kB     00:00 ...\nNo package libffi-devel available.\nError: Nothing to do
\n

可以使用下面的方法安装:

\n
[root@log01 ~]# rpm -ivh http://mirror.centos.org/centos/6/os/x86_64/Packages/libffi-devel-3.0.5-3.2.el6.x86_64.rpm\nRetrieving http://mirror.centos.org/centos/6/os/x86_64/Packages/libffi-devel-3.0.5-3.2.el6.x86_64.rpm\nwarning: /var/tmp/rpm-tmp.V9ihbu: Header V3 RSA/SHA256 Signature, key ID c105b9de: NOKEY\nPreparing...                ########################################### [100%]\n   1:libffi-devel           ########################################### [100%]\n[root@log01 ~]# rpm -qa|grep libffi\nlibffi-3.0.5-3.2.el6.x86_64\nlibffi-devel-3.0.5-3.2.el6.x86_64
\n

手动的源码方法安装如下:

\n
$ wget ftp://sourceware.org/pub/libffi/libffi-3.2.1.tar.gz\n$ tar zvxf libffi-3.2.1.tar.gz\n$ ./configure --prefix=/Bioinfo/Pipeline/SoftWare/libffi-3.2.1\n$ make\n$ make install
\n

pygraphviz

\n

如果你不需要使用 pygraphviz,可以不用管这个依赖。

\n
\n

PyGraphviz is a Python interface to the Graphviz graph layout and visualization package. With PyGraphviz you can create, edit, read, write, and draw graphs using Python to access the Graphviz graph data structure and layout algorithms.

\n
\n
\n

PyGraphviz 是 Graphviz 图形布局和可视化包的 Python 接口。 借助 PyGraphviz,您可以使用 Python 创建、编辑、读取、写入和绘制图形,以访问 Graphviz 图形数据结构和布局算法。

\n
\n
$ /Bioinfo/Pipeline/SoftWare/Python-3.7.3/bin/pip3 install pygraphviz\nCollecting pygraphviz\n  Using cached https://files.pythonhosted.org/packages/7e/b1/d6d849ddaf6f11036f9980d433f383d4c13d1ebcfc3cd09bc845bda7e433/pygraphviz-1.5.zip\nInstalling collected packages: pygraphviz\n  Running setup.py install for pygraphviz ... error\n    Complete output from command /Bioinfo/Pipeline/SoftWare/Python-3.7.3/bin/python3.7 -u -c "import setuptools, tokenize;__file__=\'/tmp/pip-install-_zdjdg0j/pygraphviz/setup.py\';f=getattr(tokenize, \'open\', open)(__file__);code=f.read().replace(\'\\r\\n\', \'\\n\');f.close();exec(compile(code, __file__, \'exec\'))" install --record /tmp/pip-record-g0mz7lrq/install-record.txt --single-version-externally-managed --compile:\n    running install\n    Trying dpkg\n    Failed to find dpkg\n    Trying pkg-config\n    Package libcgraph was not found in the pkg-config search path.\n    Perhaps you should add the directory containing `libcgraph.pc\'\n    to the PKG_CONFIG_PATH environment variable\n    No package \'libcgraph\' found\n    Traceback (most recent call last):\n      File "<string>", line 1, in <module>\n      File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup.py", line 93, in <module>\n        tests_require=[\'nose>=1.3.7\', \'doctest-ignore-unicode>=0.1.2\', \'mock>=2.0.0\'],\n      File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/site-packages/setuptools/__init__.py", line 145, in setup\n        return distutils.core.setup(**attrs)\n      File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/distutils/core.py", line 148, in setup\n        dist.run_commands()\n      File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/distutils/dist.py", line 966, in run_commands\n        self.run_command(cmd)\n      File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/distutils/dist.py", line 985, in run_command\n        cmd_obj.run()\n      File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup_commands.py", line 44, in modified_run\n        self.include_path, self.library_path = get_graphviz_dirs()\n      File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup_extra.py", line 162, in get_graphviz_dirs\n        include_dirs, library_dirs = _try_configure(include_dirs, library_dirs, _pkg_config)\n      File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup_extra.py", line 117, in _try_configure\n        i, l = try_function()\n      File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup_extra.py", line 72, in _pkg_config\n        output = S.check_output([\'pkg-config\', \'--libs-only-L\', \'libcgraph\'])\n      File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/subprocess.py", line 395, in check_output\n        **kwargs).stdout\n      File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/subprocess.py", line 487, in run\n        output=stdout, stderr=stderr)\n    subprocess.CalledProcessError: Command \'[\'pkg-config\', \'--libs-only-L\', \'libcgraph\']\' returned non-zero exit status 1.\n\n    ----------------------------------------\nCommand "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/bin/python3.7 -u -c "import setuptools, tokenize;__file__=\'/tmp/pip-install-_zdjdg0j/pygraphviz/setup.py\';f=getattr(tokenize, \'open\', open)(__file__);code=f.read().replace(\'\\r\\n\', \'\\n\');f.close();exec(compile(code, __file__, \'exec\'))" install --record /tmp/pip-record-g0mz7lrq/install-record.txt --single-version-externally-managed --compile" failed with error code 1 in /tmp/pip-install-_zdjdg0j/pygraphviz/\n
\n

参考:《Installation:fatal error: \'graphviz/cgraph.h\' file not found

\n
$ wget https://graphviz.gitlab.io/pub/graphviz/stable/SOURCES/graphviz.tar.gz\n$ tar zvxf graphviz.tar.gz\n$ cd graphviz-2.40.1\n$ ./configure --prefix=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1\n$ make && make install
\n

推荐把安装好的 graphviz 添加到环境变量,这样可以避免运行过程中出现:"pygraphviz/graphviz_wrap.c:2987:29: fatal error: graphviz/cgraph.h: No such file or directory" 无法找到头文件的异常。

\n
export PKG_CONFIG_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib/pkgconfig:$PKG_CONFIG_PATH\nexport LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib:$LD_LIBRARY_PATH\nexport C_INCLUDE_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/include:$C_INCLUDE_PATH\nexport CPLUS_INCLUDE_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/include:$CPLUS_INCLUDE_PATH
\n

如果 graphviz 添加到环境变量, pygraphviz\xa0的 python 包可以参考下面的方法安装:

\n
$ /Bioinfo/Pipeline/SoftWare/Python-3.7.3/bin/pip3 install --global-option=build_ext --global-option="-I/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/include" --global-option="-L/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib" pygraphviz\n/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/site-packages/pip/_internal/commands/install.py:207: UserWarning: Disabling all use of wheels due to the use of --build-options / --global-options / --install-options.\n  cmdoptions.check_install_build_global(options)\nCollecting pygraphviz\n  Using cached https://files.pythonhosted.org/packages/7e/b1/d6d849ddaf6f11036f9980d433f383d4c13d1ebcfc3cd09bc845bda7e433/pygraphviz-1.5.zip\nInstalling collected packages: pygraphviz\n  Running setup.py install for pygraphviz ... done\nSuccessfully installed pygraphviz-1.5
\n

编译安装

\n

这里的编译安装,以 Python-3.11.6 为示例。

\n

第一,下载 Python 源码,解压。

\n
# 官网下载地址 https://www.python.org/downloads\nwget https://www.python.org/ftp/python/3.11.6/Python-3.11.6.tgz\n\n# 解压到指定目录\ntar zvxf Python-3.11.6.tgz -C /usr/local/src
\n

第二,进入解压的源码路径,编译 Python 源码。

\n
$ export PKG_CONFIG_PATH=/Bioinfo/Pipeline/SoftWare/libffi-3.2.1/lib/pkgconfig:$PKG_CONFIG_PATH\n$ export PKG_CONFIG_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib/pkgconfig:$PKG_CONFIG_PATH\n\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/libffi-3.2.1/lib64:$LD_LIBRARY_PATH\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib:$LD_LIBRARY_PATH\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1/lib:$LD_LIBRARY_PATH\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/lib:$LD_LIBRARY_PATH\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/gdbm-1.23/lib:$LD_LIBRARY_PATH\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/lib:$LD_LIBRARY_PATH\n\n$ export TCLTK_LIBS="-L/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/lib -ltcl8.6 -ltk8.6"\n$ export TCLTK_CFLAGS="-I/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/include"\n\n$ ./configure \\\n--enable-optimizations \\\n--prefix=/Bioinfo/Pipeline/SoftWare/Python-3.11.6 \\\n--with-openssl=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1 \\\n--with-openssl-rpath=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1/lib \\\nCC=/Bioinfo/Pipeline/SoftWare/gcc-7.3.0/bin/gcc \\\nCXX=/Bioinfo/Pipeline/SoftWare/gcc-7.3.0/bin/c++ \\\nLDFLAGS="-L/Bioinfo/Pipeline/SoftWare/libffi-3.2.1/lib64 \\\n         -L/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib \\\n         -L/RiboBio/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/lib \\\n         -L/Bioinfo/Pipeline/SoftWare/gdbm-1.23/lib" \\\nCPPFLAGS="-I/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/include \\\n          -I/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/include \\\n          -I/Bioinfo/Pipeline/SoftWare/gdbm-1.23/include" \\\nPKG_CONFIG_PATH="/Bioinfo/Pipeline/SoftWare/libffi-3.2.1/lib/pkgconfig: \\\n                 /Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib/pkgconfig"
\n
    \n
  • --enable-optimizations\xa0 是优化选项(LTO,PGO\xa0 等)加上这个 \xa0flag\xa0 编译后,性能有 \xa010%\xa0 左右的优化,但是这会明显的增加编译时间。建议使用这个参数;
  • \n
  • --prefix\xa0 声明安装路径;
  • \n
  • 安装多个 python 的版本,如果不开启--enable-shared,指定不同路径即可。当开启--enable-shared 时,默认只有一个版本的 python。
  • \n
  • Python 3 编译可以在 configure 或者环境变量中指定 OpenSSL 安装路径进行编译的方式解决 OpenSSL 依赖,否则 make\xa0 过程可能出错。
  • \n
\n
$ make\n......\nThe following modules found by detect_modules() in setup.py, have been\nbuilt by the Makefile instead, as configured by the Setup files:\n_abc                  atexit                pwd\ntime\n\n\nFailed to build these modules:\n_ctypes               _hashlib              _ssl\n\n\nCould not build the ssl module!\nPython requires an OpenSSL 1.0.2 or 1.1 compatible libssl with X509_VERIFY_PARAM_set1_host().\nLibreSSL 2.6.4 and earlier do not provide the necessary APIs, https://github.com/libressl-portable/portable/issues/381\n\n......
\n\n

image.png

\n
    \n
  • 对于低版本的 Python 如果指定\xa0--with-openssl=DIR\xa0依然无法解决 ssl 模块的问题,可以参考修改 Modules/Setup.dist 文件(默认这块是注释的,放开注释即可。这块功能是开启 SSL 模块,不然会出现安装完毕后,提示找不到 ssl 模块的错误)再执行 configure,修改内容如下:
  • \n
\n
# Socket module helper for SSL support; you must comment out the other\n# socket line above, and possibly edit the SSL variable:\nSSL=/usr/local/ssl\n_ssl _ssl.c \\\n    -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \\\n    -L$(SSL)/lib -lssl -lcrypto
\n

第三,Makefile 生后依次在当前路径执行编译和安装命令。

\n
make && make install
\n

第四,安装完成。以上命令执行完毕,且无报错的情况下,我们将默认 python 换将切换至 3.11.6(一般不建议替换,个人建议把自定义安装的 Python bin 路径添加到 PATH 环境变量即可):

\n
# 替换系统自带的 python(不建议)\nmv /usr/bin/python /usr/bin/python2\nln -s /Bioinfo/Pipeline/SoftWare/Python-3.11.6/bin/python3 /usr/bin/python3\n\n# 添加新 Python 到 PATH 环境变量(建议)\necho "export PATH=/Bioinfo/Pipeline/SoftWare/Python-3.11.6/bin:$PATH" >>~/.bashrc\nsource ~/.bashrc
\n

运行命令 python -V\xa0,查看是否出现 3.11.6\xa0 的版本,出现即为安装成功。

\n

其他工具

\n

Python >= 3.10 在安装时候,默认会同时安装 pip3!如果你的 python < 3.10,可以参考下面的方法安装 pip。

\n
# 下载 setuptools 和 pip 安装程序\ncurl https://bootstrap.pypa.io/get-pip.py -o get-pip.py\npython3 get-pip.py
\n

至此,CentOS Linux release\xa06.5 下的 python-3.11.6\xa0 全部安装完成。如果在安装过程中出现其他的报错,建议把 error 关键信息直接复制到 Google 进行检索,参考其他人的解决方法。

\n

其他异常与解决

\n

_bz2

\n
    \n
  • 系统:CentOS Linux release 7.7.1908 (Core)
  • \n
  • GCC:gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39)
  • \n
\n

在 CentOS 7 中安装 Python-3.6.9 中发现 make 过程中一直提示:"ModuleNotFoundError: No module named \'_bz2\'",尽管 sudo yum install bzip2 bzip2-devel\xa0 已经安装了 bzip2 的依赖,问题还是不得其解。最后参考 stackoverflow 上的《Correctly building local python3, with bz2 support》,终于解决问题,下面记录一下。
\nCorrectly building local python3, with bz2 support

\n

手动安装 bzip2:

\n
wget https://nchc.dl.sourceforge.net/project/bzip2/bzip2-1.0.6.tar.gz\ntar zvxf bzip2-1.0.6.tar.gz\ncd bzip2-1.0.6\nmake -f Makefile_libbz2_so  # 这一步是生成 libbz2.so.1.0.6 的动态库文件\nmake\nmake install PREFIX=/usr/local/software/bzip2-1.0.6\ncp libbz2.so.1.0.6 /usr/local/software/bzip2-1.0.6/lib/
\n

几点说明:

\n
    \n
  • bzip2 的官网 \xa0http://www.bzip.org/\xa0 已经把 bzip2 的源码下载链接放到了 \xa0SourceForge,网络上一些从 \xa0http://www.bzip.org/1.0.6/bzip2-1.0.6.tar.gz\xa0 下载的做法已经失效。
  • \n
  • SourceForge 上 bzip2 的最新版本还是 1.0.6(Last modified 2018-11-3),更高级版本的 bzip2 我也不知道是否存在,也不知道能不能用。
  • \n
\n

image.png

\n

编译安装 Python-3.6.9:

\n
$ wget https://www.python.org/ftp/python/3.6.9/Python-3.6.9.tgz\n$ tar zvxf Python-3.6.9.tgz\n$ cd Python-3.6.9\n$ ./configure --enable-optimizations --prefix=/usr/local/software/python-3.6 CFLAGS="-I/usr/local/software/bzip2-1.0.6/include" LDFLAGS="-L/usr/local/software/bzip2-1.0.6/lib"\n$ make\n$ make install
\n
    \n
  • Python-3.6.9 中的 ./configure --help\xa0中没有 --with-openssl\xa0参数!有点神奇,我也不知道原因。
  • \n
  • 安装完成可以用 from _bz2 import BZ2Compressor, BZ2Decompressor\xa0测试一下 _bz2\xa0 是否可用。
  • \n
\n

参考资料

\n
    \n
  1. 行者无疆-ITer,《python2.7 源码编译安装》, 博客园
  2. \n
  3. Scott Frazer,《How do I compile Python 3.4 with custom OpenSSL?》, Stack Overflow
  4. \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '1.3.5-Python'}]}, 'comments': {'nodes': []}}, {'title': 'Python 中 tkinter 源码安装使用与中文乱码', 'number': 12, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/12', 'createdAt': '2023-11-02T02:24:22Z', 'lastEditedAt': '2024-10-15T02:30:26Z', 'updatedAt': '2024-10-15T02:30:26Z', 'body': '主要是因为下面这两个原因,所以决定从源码编译安装去折腾一下 tkinter,以下是一些记录。\r\n\r\n## _tkinter not found\r\n\r\nPython 3 源码编译安装,执行 `make` 过程中提示 `_tkinter not found`,如下:\r\n```bash\r\n$ make\r\n......\r\nPython build finished successfully!\r\nThe necessary bits to build these optional modules were not found:\r\n_tkinter \r\n```\r\n\r\n## 中文乱码\r\n\r\n使用 Anaconda 3(conda 4.5.11)的 tkinter python 包(conda install -c conda-forge tk)开发 GUI 界面程序过程中,发现 UI 界面出现的中文 Unicode 乱码一直没办法解决。\r\n\r\n```python\r\n#-*- coding: utf-8 -*-\r\n\r\nimport sys\r\n\r\nfrom tkinter import *\r\ntop=Tk()\r\ntop.wm_title("菜单")\r\ntop.geometry("800x600+300+100") # 创建一个菜单项,类似于导航栏\r\nmenubar=Menu(top) # 创建菜单项\r\nfmenu1=Menu(top)\r\n# 如果该菜单时顶层菜单的一个菜单项,则它添加的是下拉菜单的菜单\r\nfor item in [\'新建文件\', \'打开文件\',\'结果保存\']:\r\n fmenu1.add_command(label=item)\r\n\r\nfmenu2=Menu(top)\r\nfor item in [\'程序设置\',\'程序运行\']:\r\n fmenu2.add_command(label=item)\r\n\r\nfmenu3=Menu(top)\r\nfor item in [\'使用教程\', \'版权信息\', \'检查更新\']:\r\n fmenu3.add_command(label=item)\r\n\r\n# add_cascade 的一个很重要的属性就是 menu 属性,它指明了要把那个菜单级联到该菜单项上\r\n# 当然,还必不可少的就是 label 属性,用于指定该菜单项的名称\r\nmenubar.add_cascade(label=\'文件\', menu=fmenu1)\r\nmenubar.add_cascade(label="程序", menu=fmenu2)\r\nmenubar.add_cascade(label="帮助", menu=fmenu3)\r\n\r\n# 最后可以用窗口的 menu 属性指定我们使用哪一个作为它的顶层菜单\r\ntop[\'menu\']=menubar\r\ntop.mainloop()\r\n```\r\n\r\n![](https://shub.weiyan.tech/yuque/elog-cookbook-img/Fh22i487OzvY-uSXvAuFs6rEXXvu.png)\r\n\r\n我们也可以确认一下是不是 Tk 本身的问题:\r\n```\r\necho \'pack [button .h -text "Hello, World! 显示中文" -command exit]\' | wish\r\n```\r\n- 正常显示\r\n ![TK 正常显示](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/tk-ok.png)\r\n\r\n- 中文乱码\r\n ![TK 中文乱码](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/tk-error.png)\r\n\r\n**一些参考资料:**\r\n\r\n- Python 3.x 中文编码转换的问题:\r\n- Python 2.6 Tk 中文乱码解決方法:\r\n- tkinter 乱码,pyqt4 乱码:\r\n\r\n上面几种方法测试后,问题依然存在。在 google 上一番搜索和来回测试之后,发现了几点信息:\r\n\r\n- 有人说,可能是 tcl/tk 安装不完整造成的。\r\n- tcl/tk 重装后需要对 Python 重新编译 tkinter 才能起作用。\r\n- conda install -c conda-forge tk,虽然没有任何报错,python2 中 import tkinter 也正常,但 conda 的软件安装就像一个黑盒子,无法确认 tcl/tk 是否完整安装。\r\n- python 的 PyPI 仓库中是没有 tkinter 包的,想要使用 `pip install tkinter` 卸载或者重装都是行不通的。\r\n- 网上也有人说可以使用 `yum install python3-tk/python-tk` 解决,但对于本人来说,没用。\r\n\r\n## 什么是 tcl, tk, tkinter\r\n\r\n> The\xa0[tkinter](https://docs.python.org/3.6/library/tkinter.html#module-tkinter)\xa0package (“Tk interface”) is the standard Python interface to the Tk GUI toolkit. Both Tk and\xa0[tkinter](https://docs.python.org/3.6/library/tkinter.html#module-tkinter)\xa0are available on most Unix platforms, as well as on Windows systems. (Tk itself is not part of Python; it is maintained at ActiveState.)\r\n>\r\n> Running\xa0`python\xa0-m\xa0tkinter`\xa0from the command line should open a window demonstrating a simple Tk interface, letting you know that\xa0[tkinter](https://docs.python.org/3.6/library/tkinter.html#module-tkinter)\xa0is properly installed on your system, and also showing what version of Tcl/Tk is installed, so you can read the Tcl/Tk documentation specific to that version.\r\n>\r\n> From \r\n\r\nTcl 是"工具控制语言(Tool Control Language)"的缩写。Tk 是 Tcl "图形工具箱" 的扩展,它提供各种标准的 GUI 接口项,以利于迅速进行高级应用程序开发。\r\n\r\ntkinter 包("Tk 接口")是 Tk GUI 工具包的标准 Python 接口。 Tk 和 \xa0tkinter 在大多数 Unix 平台以及 Windows 系统上都可用(Tk 本身不是 Python 的一部分,它在 ActiveState 中维护)。您可以通过从命令行运行 \xa0`python -m\xa0tkinter`来检查 \xa0tkinter 是否已正确安装在系统上。如果已经安装该命令会打开一个简单的 Tk 界面,该界面除了让我们知道 tkinter 已正确安装,并且还显示安装了哪个版本的 Tcl/Tk,因此我们可以阅读特定于该版本的 Tcl/Tk 文档。\r\n\r\n![](https://shub.weiyan.tech/yuque/elog-cookbook-img/FpWx6rSTKaQ1BXXPQJzchNbviKYd.png)\r\n\r\n如果 \xa0tkinter\xa0 没有安装,则会提示找不到该包(注意在 Python 2 中该包包名为 Tkinter,Python 3 中为 tkinter):\r\n\r\n![](https://shub.weiyan.tech/yuque/elog-cookbook-img/FrRwzLFA1tIq2VfwS4p7i0dVLTjP.png)\r\n\r\n接下来我们将尝试在 Python 2/3 中安装 Tcl/Tk,并重新编译 Python 2/3,已完成 Tkinter 安装(tkinter 为 Python 的标准库,标准库的安装需要重新编译 Python ?)。\r\n\r\n## ActiveTcl 安装\r\n\r\nActiveTcl 是 ActiveState 发布的关于 Tcl/Tk 的发行版本,该发行版本包含了最新版本的 Tk 和 Tcl 程序,我们下载其免费的社区版本进行安装即可。\r\n\r\n参考下载链接:\r\n参考安装教程:\r\n\r\n以下为 CentOS 6.5 下 **ActiveTcl-8.6.9** 的一些安装记录,仅作参考。\r\n\r\n```bash\r\n$ curl -fL "https://shenweiyan-generic.pkg.coding.net/btscl/activetcl/ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d.tar.gz?version=8.6.9.8609.2" -o ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d.tar.gz\r\n$ tar zvxf ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d.tar.gz\r\n$ cd ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d\r\n$ ./install.sh\r\n......\r\nCancel [no] => [RET]\r\nAccept License [yes] => \'A\' >>A\r\n\r\nPlease specify the installation directory.\r\nPath [/opt/ActiveTcl-8.6]: /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9\r\n\r\nPlease specify the directory for the demos.\r\nPath [/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/demos]:\r\n\r\nPlease specify the runtime installation directory.\r\n\r\nThis is the directory the applications will see as their installation directory\r\nwhen searching for packages and libraries, instead of the directory the files\r\nwere copied to. In most circumstances this is the same as the installation\r\ndirectory chosen before.\r\nPath [/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9]:\r\n\r\nPress return to begin installation\r\n Installation Directory: /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9\r\n Demos Directory: /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/demos\r\n Runtime Directory: See Installation Directory\r\nCancel => C\r\nNext => [RET] >>\r\n\r\nInstalling ActiveTcl ...\r\n Creating directory /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/share ...\r\n Creating directory /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/share/man ...\r\n ......\r\n\r\nPlease do not forget to extend your PATH and MANPATH variables to\r\nget access to the applications and manpages distributed with ActiveTcl.\r\n\r\nFor a csh or compatible perform\r\n setenv PATH "/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/bin:$PATH"\r\n\r\nFor a sh or similar perform\r\n PATH="/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/bin:$PATH"\r\n export PATH\r\n\r\nSome shells (bash for example) allow\r\n export PATH="/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/bin:$PATH"\r\n\r\nSimilar changes are required for MANPATH\r\nFinish >>\r\n```\r\n\r\nActiveTcl 安装完成后,需要把 path 添加至环境变量(\\~/.bashrc):\r\n```\r\nexport PATH="/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/bin:$PATH"\r\n```\r\n\r\n## Tcl/Tk\r\n\r\n我们也可以直接去 直接通过源码的方式去编译安装 Tcl/Tk,尤其是当你的系统版本比较低,需要低版本的 Tcl/Tk,这种方法会比较合适。\r\n\r\n以 tcl8.5.19-src.tar.gz/tk8.5.19-src.tar.gz 为例,下载完成后,直接解压,然后执行常规安装即可。\r\n```\r\ncd tcl8.5.19/unix\r\n./configure\r\nmake\r\nmake test\r\nmake install\r\n```\r\n\r\n## Python 重新编译安装\r\n\r\n参考:[What’s New In Python 3.11](https://docs.python.org/3/whatsnew/3.11.html) - doc.python.org\r\n\r\n> 📢 **注意:**\r\n>\r\n> 1. Python 3.11.x 起(如 Python-3.11.3)中的 `configure` 已经把 `--with-tcltk-includes`和`--with-tcltk-libs`这两个参数移除!并使用 `TCLTK_CFLAGS` 和 `TCLTK_LIBS` 替代!!!\r\n> 2. Python 3.10.x (及以下版本,如 Python-3.9.16) 以及 Python 2.x.x 在 `configure` 中 `--with-tcltk-includes`和`--with-tcltk-libs`都是有的,通过这两个参数可以解决 Tkinter 的问题!!!\r\n\r\n### Python 3\r\n\r\n这里以 Python-3.11.6 为例,参考 [Python 3.11.0 install doesn’t recognize homebrew Tcl/Tk due to --with-tcltk-libs, --with-tcltk-includes switches being removed from 3.11 - pyenv#2499](https://github.com/pyenv/pyenv/issues/2499),在编译安装过程中使用 `TCLTK_CFLAGS` 和 `TCLTK_LIBS` 解决 `_tkinter` 缺失的问题。\r\n```\r\nexport TCLTK_LIBS="-L/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/lib -ltcl8.6 -ltk8.6" # 8.5.x 版本,需改为 -ltcl8.5 -ltk8.5\r\nexport TCLTK_CFLAGS="-I/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/include"\r\n\r\ncd Python-3.11.6\r\n/configure --prefix=/Bioinfo/Pipeline/SoftWare/python-3.11.6 ......\r\nmake && make install\r\n```\r\n\r\n![python3-confiigure-tkinter-yes](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/python-3-tkinter.png)\r\n\r\n对于 Python 3.10.x (及以下版本,如 Python-3.9.18),`configure` 中 `--with-tcltk-includes` 和 `--with-tcltk-libs` 的具体使用参考 : \r\n \r\n![tcltk-issue-21887-msg](https://kg.weiyan.cc/2024/10/tcltk-issue-21887-msg.webp)\r\n\r\n### Python 2\r\n\r\n想要在 Python 2.7 安装 Tkinter,需要在编译过程中通过 `--with-tcltk-includes` 和 `--with-tcltk-libs` 中指定 ActiveTcl 的头文件以及库所在路径。\r\n\r\n如果在执行编译安装过程中,出现无法找到 libXss.so.1 共享动态库报错:\r\n\r\n```bash\r\n$ tar zvxf Python-2.7.15.tgz\r\n$ cd Python-2.7.15\r\n$ ./configure --prefix=/usr/local/software/python-2.7 --with-tcltk-includes=\'-I/usr/local/software/ActiveTcl-8.6/include\' --with-tcltk-libs=\'-L/usr/local/software/ActiveTcl-8.6/lib -ltcl8.6 -ltk8.6\' --enable-optimizations\r\n$ make\r\n\r\n......\r\n\r\nwarning: building with the bundled copy of libffi is deprecated on this platform. It will not be distributed with Python 3.7\r\n*** WARNING: renaming "_tkinter" since importing it failed: libXss.so.1: cannot open shared object file: No such file or directory\r\n\r\nPython build finished successfully!\r\nThe necessary bits to build these optional modules were not found:\r\n_dbm _gdbm\r\nTo find the necessary bits, look in setup.py in detect_modules() for the module\'s name.\r\n\r\nThe following modules found by detect_modules() in setup.py, have been\r\nbuilt by the Makefile instead, as configured by the Setup files:\r\natexit pwd time\r\n\r\nFollowing modules built successfully but were removed because they could not be imported:\r\n_tkinter\r\n\r\nrunning build_scripts\r\n\r\n......\r\n```\r\n\r\nCentOS 下请参考以下解决方法:\r\n```\r\n$ sudo yum install libXScrnSaver libXScrnSaver-devel\r\n```\r\n\r\n## 调用 Tkinter\r\n\r\nPython 2/3 重新编译完后,执行一下下面的命令即可显示 Tk 的 ui 界面,以及相应的 Tcl/Tk 版本。\r\n```\r\npython2 -m Tkinter # python 2\r\npython3 -m tkinter # python 3\r\n```\r\n![python2-m-Tkinter](https://shub.weiyan.tech/yuque/elog-cookbook-img/FgBtb14ZgZFZXIRhOdt6efbYz7fd.png)\r\n\r\n这时候,我们重新运行开头的 GUI 界面程序,可以看到中文已经正常显示:\r\n![](https://shub.weiyan.tech/yuque/elog-cookbook-img/FqRHUXczPdHrQjFUXNQr_Cg_j2B4.png)\r\n\r\n## 参考资料\r\n\r\n- Download And Install Tcl: ActiveTcl,\r\n- Installing Tk,\r\n- Python 下"No module named \\_tkinter"问题解决过程分析,\r\n- Python GUI 编程(Tkinter)文件对话框,\r\n', 'bodyText': '主要是因为下面这两个原因,所以决定从源码编译安装去折腾一下 tkinter,以下是一些记录。\n_tkinter not found\nPython 3 源码编译安装,执行 make 过程中提示 _tkinter not found,如下:\n$ make\n......\nPython build finished successfully!\nThe necessary bits to build these optional modules were not found:\n_tkinter \n中文乱码\n使用 Anaconda 3(conda 4.5.11)的 tkinter python 包(conda install -c conda-forge tk)开发 GUI 界面程序过程中,发现 UI 界面出现的中文 Unicode 乱码一直没办法解决。\n#-*- coding: utf-8 -*-\n\nimport sys\n\nfrom tkinter import *\ntop=Tk()\ntop.wm_title("菜单")\ntop.geometry("800x600+300+100") # 创建一个菜单项,类似于导航栏\nmenubar=Menu(top) # 创建菜单项\nfmenu1=Menu(top)\n# 如果该菜单时顶层菜单的一个菜单项,则它添加的是下拉菜单的菜单\nfor item in [\'新建文件\', \'打开文件\',\'结果保存\']:\n fmenu1.add_command(label=item)\n\nfmenu2=Menu(top)\nfor item in [\'程序设置\',\'程序运行\']:\n fmenu2.add_command(label=item)\n\nfmenu3=Menu(top)\nfor item in [\'使用教程\', \'版权信息\', \'检查更新\']:\n fmenu3.add_command(label=item)\n\n# add_cascade 的一个很重要的属性就是 menu 属性,它指明了要把那个菜单级联到该菜单项上\n# 当然,还必不可少的就是 label 属性,用于指定该菜单项的名称\nmenubar.add_cascade(label=\'文件\', menu=fmenu1)\nmenubar.add_cascade(label="程序", menu=fmenu2)\nmenubar.add_cascade(label="帮助", menu=fmenu3)\n\n# 最后可以用窗口的 menu 属性指定我们使用哪一个作为它的顶层菜单\ntop[\'menu\']=menubar\ntop.mainloop()\n\n我们也可以确认一下是不是 Tk 本身的问题:\necho \'pack [button .h -text "Hello, World! 显示中文" -command exit]\' | wish\n\n\n\n正常显示\n\n\n\n中文乱码\n\n\n\n一些参考资料:\n\nPython 3.x 中文编码转换的问题:https://bbs.bccn.net/thread-479560-1-1.html\nPython 2.6 Tk 中文乱码解決方法:http://blogkrogh.blogspot.com/2011/03/python-26-tk.html\ntkinter 乱码,pyqt4 乱码:http://aboutweb.lofter.com/post/11743e_6f7e4a5\n\n上面几种方法测试后,问题依然存在。在 google 上一番搜索和来回测试之后,发现了几点信息:\n\n有人说,可能是 tcl/tk 安装不完整造成的。\ntcl/tk 重装后需要对 Python 重新编译 tkinter 才能起作用。\nconda install -c conda-forge tk,虽然没有任何报错,python2 中 import tkinter 也正常,但 conda 的软件安装就像一个黑盒子,无法确认 tcl/tk 是否完整安装。\npython 的 PyPI 仓库中是没有 tkinter 包的,想要使用 pip install tkinter 卸载或者重装都是行不通的。\n网上也有人说可以使用 yum install python3-tk/python-tk 解决,但对于本人来说,没用。\n\n什么是 tcl, tk, tkinter\n\nThe\xa0tkinter\xa0package (“Tk interface”) is the standard Python interface to the Tk GUI toolkit. Both Tk and\xa0tkinter\xa0are available on most Unix platforms, as well as on Windows systems. (Tk itself is not part of Python; it is maintained at ActiveState.)\nRunning\xa0python\xa0-m\xa0tkinter\xa0from the command line should open a window demonstrating a simple Tk interface, letting you know that\xa0tkinter\xa0is properly installed on your system, and also showing what version of Tcl/Tk is installed, so you can read the Tcl/Tk documentation specific to that version.\nFrom https://docs.python.org/3/library/tkinter.html\n\nTcl 是"工具控制语言(Tool Control Language)"的缩写。Tk 是 Tcl "图形工具箱" 的扩展,它提供各种标准的 GUI 接口项,以利于迅速进行高级应用程序开发。\ntkinter 包("Tk 接口")是 Tk GUI 工具包的标准 Python 接口。 Tk 和 \xa0tkinter 在大多数 Unix 平台以及 Windows 系统上都可用(Tk 本身不是 Python 的一部分,它在 ActiveState 中维护)。您可以通过从命令行运行 \xa0python -m\xa0tkinter来检查 \xa0tkinter 是否已正确安装在系统上。如果已经安装该命令会打开一个简单的 Tk 界面,该界面除了让我们知道 tkinter 已正确安装,并且还显示安装了哪个版本的 Tcl/Tk,因此我们可以阅读特定于该版本的 Tcl/Tk 文档。\n\n如果 \xa0tkinter\xa0 没有安装,则会提示找不到该包(注意在 Python 2 中该包包名为 Tkinter,Python 3 中为 tkinter):\n\n接下来我们将尝试在 Python 2/3 中安装 Tcl/Tk,并重新编译 Python 2/3,已完成 Tkinter 安装(tkinter 为 Python 的标准库,标准库的安装需要重新编译 Python ?)。\nActiveTcl 安装\nActiveTcl 是 ActiveState 发布的关于 Tcl/Tk 的发行版本,该发行版本包含了最新版本的 Tk 和 Tcl 程序,我们下载其免费的社区版本进行安装即可。\n参考下载链接:https://www.activestate.com/products/activetcl/downloads/\n参考安装教程:https://tkdocs.com/tutorial/install.html\n以下为 CentOS 6.5 下 ActiveTcl-8.6.9 的一些安装记录,仅作参考。\n$ curl -fL "https://shenweiyan-generic.pkg.coding.net/btscl/activetcl/ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d.tar.gz?version=8.6.9.8609.2" -o ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d.tar.gz\n$ tar zvxf ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d.tar.gz\n$ cd ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d\n$ ./install.sh\n......\nCancel [no] => [RET]\nAccept License [yes] => \'A\' >>A\n\nPlease specify the installation directory.\nPath [/opt/ActiveTcl-8.6]: /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9\n\nPlease specify the directory for the demos.\nPath [/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/demos]:\n\nPlease specify the runtime installation directory.\n\nThis is the directory the applications will see as their installation directory\nwhen searching for packages and libraries, instead of the directory the files\nwere copied to. In most circumstances this is the same as the installation\ndirectory chosen before.\nPath [/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9]:\n\nPress return to begin installation\n Installation Directory: /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9\n Demos Directory: /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/demos\n Runtime Directory: See Installation Directory\nCancel => C\nNext => [RET] >>\n\nInstalling ActiveTcl ...\n Creating directory /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/share ...\n Creating directory /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/share/man ...\n ......\n\nPlease do not forget to extend your PATH and MANPATH variables to\nget access to the applications and manpages distributed with ActiveTcl.\n\nFor a csh or compatible perform\n setenv PATH "/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/bin:$PATH"\n\nFor a sh or similar perform\n PATH="/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/bin:$PATH"\n export PATH\n\nSome shells (bash for example) allow\n export PATH="/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/bin:$PATH"\n\nSimilar changes are required for MANPATH\nFinish >>\nActiveTcl 安装完成后,需要把 path 添加至环境变量(~/.bashrc):\nexport PATH="/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/bin:$PATH"\n\nTcl/Tk\n我们也可以直接去 https://sourceforge.net/projects/tcl/files/Tcl/ 直接通过源码的方式去编译安装 Tcl/Tk,尤其是当你的系统版本比较低,需要低版本的 Tcl/Tk,这种方法会比较合适。\n以 tcl8.5.19-src.tar.gz/tk8.5.19-src.tar.gz 为例,下载完成后,直接解压,然后执行常规安装即可。\ncd tcl8.5.19/unix\n./configure\nmake\nmake test\nmake install\n\nPython 重新编译安装\n参考:What’s New In Python 3.11 - doc.python.org\n\n📢 注意:\n\nPython 3.11.x 起(如 Python-3.11.3)中的 configure 已经把 --with-tcltk-includes和--with-tcltk-libs这两个参数移除!并使用 TCLTK_CFLAGS 和 TCLTK_LIBS 替代!!!\nPython 3.10.x (及以下版本,如 Python-3.9.16) 以及 Python 2.x.x 在 configure 中 --with-tcltk-includes和--with-tcltk-libs都是有的,通过这两个参数可以解决 Tkinter 的问题!!!\n\n\nPython 3\n这里以 Python-3.11.6 为例,参考 Python 3.11.0 install doesn’t recognize homebrew Tcl/Tk due to --with-tcltk-libs, --with-tcltk-includes switches being removed from 3.11 - pyenv#2499,在编译安装过程中使用 TCLTK_CFLAGS 和 TCLTK_LIBS 解决 _tkinter 缺失的问题。\nexport TCLTK_LIBS="-L/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/lib -ltcl8.6 -ltk8.6" # 8.5.x 版本,需改为 -ltcl8.5 -ltk8.5\nexport TCLTK_CFLAGS="-I/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/include"\n\ncd Python-3.11.6\n/configure --prefix=/Bioinfo/Pipeline/SoftWare/python-3.11.6 ......\nmake && make install\n\n\n对于 Python 3.10.x (及以下版本,如 Python-3.9.18),configure 中 --with-tcltk-includes 和 --with-tcltk-libs 的具体使用参考 https://bugs.python.org/issue21887:\n\nPython 2\n想要在 Python 2.7 安装 Tkinter,需要在编译过程中通过 --with-tcltk-includes 和 --with-tcltk-libs 中指定 ActiveTcl 的头文件以及库所在路径。\n如果在执行编译安装过程中,出现无法找到 libXss.so.1 共享动态库报错:\n$ tar zvxf Python-2.7.15.tgz\n$ cd Python-2.7.15\n$ ./configure --prefix=/usr/local/software/python-2.7 --with-tcltk-includes=\'-I/usr/local/software/ActiveTcl-8.6/include\' --with-tcltk-libs=\'-L/usr/local/software/ActiveTcl-8.6/lib -ltcl8.6 -ltk8.6\' --enable-optimizations\n$ make\n\n......\n\nwarning: building with the bundled copy of libffi is deprecated on this platform. It will not be distributed with Python 3.7\n*** WARNING: renaming "_tkinter" since importing it failed: libXss.so.1: cannot open shared object file: No such file or directory\n\nPython build finished successfully!\nThe necessary bits to build these optional modules were not found:\n_dbm _gdbm\nTo find the necessary bits, look in setup.py in detect_modules() for the module\'s name.\n\nThe following modules found by detect_modules() in setup.py, have been\nbuilt by the Makefile instead, as configured by the Setup files:\natexit pwd time\n\nFollowing modules built successfully but were removed because they could not be imported:\n_tkinter\n\nrunning build_scripts\n\n......\nCentOS 下请参考以下解决方法:\n$ sudo yum install libXScrnSaver libXScrnSaver-devel\n\n调用 Tkinter\nPython 2/3 重新编译完后,执行一下下面的命令即可显示 Tk 的 ui 界面,以及相应的 Tcl/Tk 版本。\npython2 -m Tkinter # python 2\npython3 -m tkinter # python 3\n\n\n这时候,我们重新运行开头的 GUI 界面程序,可以看到中文已经正常显示:\n\n参考资料\n\nDownload And Install Tcl: ActiveTcl,https://www.activestate.com/products/activetcl/downloads/\nInstalling Tk,https://tkdocs.com/tutorial/install.html\nPython 下"No module named _tkinter"问题解决过程分析,https://www.jianshu.com/p/0baa9657377f\nPython GUI 编程(Tkinter)文件对话框,https://my.oschina.net/u/2245781/blog/661533', 'bodyHTML': '

主要是因为下面这两个原因,所以决定从源码编译安装去折腾一下 tkinter,以下是一些记录。

\n

_tkinter not found

\n

Python 3 源码编译安装,执行 make 过程中提示 _tkinter not found,如下:

\n
$ make\n......\nPython build finished successfully!\nThe necessary bits to build these optional modules were not found:\n_tkinter 
\n

中文乱码

\n

使用 Anaconda 3(conda 4.5.11)的 tkinter python 包(conda install -c conda-forge tk)开发 GUI 界面程序过程中,发现 UI 界面出现的中文 Unicode 乱码一直没办法解决。

\n
#-*- coding: utf-8 -*-\n\nimport sys\n\nfrom tkinter import *\ntop=Tk()\ntop.wm_title("菜单")\ntop.geometry("800x600+300+100") # 创建一个菜单项,类似于导航栏\nmenubar=Menu(top) # 创建菜单项\nfmenu1=Menu(top)\n# 如果该菜单时顶层菜单的一个菜单项,则它添加的是下拉菜单的菜单\nfor item in [\'新建文件\', \'打开文件\',\'结果保存\']:\n    fmenu1.add_command(label=item)\n\nfmenu2=Menu(top)\nfor item in [\'程序设置\',\'程序运行\']:\n    fmenu2.add_command(label=item)\n\nfmenu3=Menu(top)\nfor item in [\'使用教程\', \'版权信息\', \'检查更新\']:\n    fmenu3.add_command(label=item)\n\n# add_cascade 的一个很重要的属性就是 menu 属性,它指明了要把那个菜单级联到该菜单项上\n# 当然,还必不可少的就是 label 属性,用于指定该菜单项的名称\nmenubar.add_cascade(label=\'文件\', menu=fmenu1)\nmenubar.add_cascade(label="程序", menu=fmenu2)\nmenubar.add_cascade(label="帮助", menu=fmenu3)\n\n# 最后可以用窗口的 menu 属性指定我们使用哪一个作为它的顶层菜单\ntop[\'menu\']=menubar\ntop.mainloop()
\n

\n

我们也可以确认一下是不是 Tk 本身的问题:

\n
echo \'pack [button .h -text "Hello, World! 显示中文" -command exit]\' | wish\n
\n
    \n
  • \n

    正常显示
    \nTK 正常显示

    \n
  • \n
  • \n

    中文乱码
    \nTK 中文乱码

    \n
  • \n
\n

一些参考资料:

\n\n

上面几种方法测试后,问题依然存在。在 google 上一番搜索和来回测试之后,发现了几点信息:

\n
    \n
  • 有人说,可能是 tcl/tk 安装不完整造成的。
  • \n
  • tcl/tk 重装后需要对 Python 重新编译 tkinter 才能起作用。
  • \n
  • conda install -c conda-forge tk,虽然没有任何报错,python2 中 import tkinter 也正常,但 conda 的软件安装就像一个黑盒子,无法确认 tcl/tk 是否完整安装。
  • \n
  • python 的 PyPI 仓库中是没有 tkinter 包的,想要使用 pip install tkinter 卸载或者重装都是行不通的。
  • \n
  • 网上也有人说可以使用 yum install python3-tk/python-tk 解决,但对于本人来说,没用。
  • \n
\n

什么是 tcl, tk, tkinter

\n
\n

The\xa0tkinter\xa0package (“Tk interface”) is the standard Python interface to the Tk GUI toolkit. Both Tk and\xa0tkinter\xa0are available on most Unix platforms, as well as on Windows systems. (Tk itself is not part of Python; it is maintained at ActiveState.)

\n

Running\xa0python\xa0-m\xa0tkinter\xa0from the command line should open a window demonstrating a simple Tk interface, letting you know that\xa0tkinter\xa0is properly installed on your system, and also showing what version of Tcl/Tk is installed, so you can read the Tcl/Tk documentation specific to that version.

\n

From https://docs.python.org/3/library/tkinter.html

\n
\n

Tcl 是"工具控制语言(Tool Control Language)"的缩写。Tk 是 Tcl "图形工具箱" 的扩展,它提供各种标准的 GUI 接口项,以利于迅速进行高级应用程序开发。

\n

tkinter 包("Tk 接口")是 Tk GUI 工具包的标准 Python 接口。 Tk 和 \xa0tkinter 在大多数 Unix 平台以及 Windows 系统上都可用(Tk 本身不是 Python 的一部分,它在 ActiveState 中维护)。您可以通过从命令行运行 \xa0python -m\xa0tkinter来检查 \xa0tkinter 是否已正确安装在系统上。如果已经安装该命令会打开一个简单的 Tk 界面,该界面除了让我们知道 tkinter 已正确安装,并且还显示安装了哪个版本的 Tcl/Tk,因此我们可以阅读特定于该版本的 Tcl/Tk 文档。

\n

\n

如果 \xa0tkinter\xa0 没有安装,则会提示找不到该包(注意在 Python 2 中该包包名为 Tkinter,Python 3 中为 tkinter):

\n

\n

接下来我们将尝试在 Python 2/3 中安装 Tcl/Tk,并重新编译 Python 2/3,已完成 Tkinter 安装(tkinter 为 Python 的标准库,标准库的安装需要重新编译 Python ?)。

\n

ActiveTcl 安装

\n

ActiveTcl 是 ActiveState 发布的关于 Tcl/Tk 的发行版本,该发行版本包含了最新版本的 Tk 和 Tcl 程序,我们下载其免费的社区版本进行安装即可。

\n

参考下载链接:https://www.activestate.com/products/activetcl/downloads/
\n参考安装教程:https://tkdocs.com/tutorial/install.html

\n

以下为 CentOS 6.5 下 ActiveTcl-8.6.9 的一些安装记录,仅作参考。

\n
$ curl -fL "https://shenweiyan-generic.pkg.coding.net/btscl/activetcl/ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d.tar.gz?version=8.6.9.8609.2" -o ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d.tar.gz\n$ tar zvxf ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d.tar.gz\n$ cd ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d\n$ ./install.sh\n......\nCancel         [no]  => [RET]\nAccept License [yes] => \'A\' >>A\n\nPlease specify the installation directory.\nPath [/opt/ActiveTcl-8.6]: /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9\n\nPlease specify the directory for the demos.\nPath [/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/demos]:\n\nPlease specify the runtime installation directory.\n\nThis is the directory the applications will see as their installation directory\nwhen searching for packages and libraries, instead of the directory the files\nwere copied to. In most circumstances this is the same as the installation\ndirectory chosen before.\nPath [/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9]:\n\nPress return to begin installation\n     Installation Directory:  /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9\n     Demos Directory:         /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/demos\n     Runtime Directory:       See Installation Directory\nCancel => C\nNext   => [RET] >>\n\nInstalling ActiveTcl ...\n        Creating directory /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/share ...\n        Creating directory /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/share/man ...\n        ......\n\nPlease do not forget to extend your PATH and MANPATH variables to\nget access to the applications and manpages distributed with ActiveTcl.\n\nFor a csh or compatible perform\n    setenv PATH "/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/bin:$PATH"\n\nFor a sh or similar perform\n    PATH="/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/bin:$PATH"\n    export PATH\n\nSome shells (bash for example) allow\n    export PATH="/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/bin:$PATH"\n\nSimilar changes are required for MANPATH\nFinish >>
\n

ActiveTcl 安装完成后,需要把 path 添加至环境变量(~/.bashrc):

\n
export PATH="/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/bin:$PATH"\n
\n

Tcl/Tk

\n

我们也可以直接去 https://sourceforge.net/projects/tcl/files/Tcl/ 直接通过源码的方式去编译安装 Tcl/Tk,尤其是当你的系统版本比较低,需要低版本的 Tcl/Tk,这种方法会比较合适。

\n

以 tcl8.5.19-src.tar.gz/tk8.5.19-src.tar.gz 为例,下载完成后,直接解压,然后执行常规安装即可。

\n
cd tcl8.5.19/unix\n./configure\nmake\nmake test\nmake install\n
\n

Python 重新编译安装

\n

参考:What’s New In Python 3.11 - doc.python.org

\n
\n

📢 注意:

\n
    \n
  1. Python 3.11.x 起(如 Python-3.11.3)中的 configure 已经把 --with-tcltk-includes--with-tcltk-libs这两个参数移除!并使用 TCLTK_CFLAGSTCLTK_LIBS 替代!!!
  2. \n
  3. Python 3.10.x (及以下版本,如 Python-3.9.16) 以及 Python 2.x.x 在 configure--with-tcltk-includes--with-tcltk-libs都是有的,通过这两个参数可以解决 Tkinter 的问题!!!
  4. \n
\n
\n

Python 3

\n

这里以 Python-3.11.6 为例,参考 Python 3.11.0 install doesn’t recognize homebrew Tcl/Tk due to --with-tcltk-libs, --with-tcltk-includes switches being removed from 3.11 - pyenv#2499,在编译安装过程中使用 TCLTK_CFLAGSTCLTK_LIBS 解决 _tkinter 缺失的问题。

\n
export TCLTK_LIBS="-L/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/lib -ltcl8.6 -ltk8.6"  # 8.5.x 版本,需改为 -ltcl8.5 -ltk8.5\nexport TCLTK_CFLAGS="-I/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/include"\n\ncd Python-3.11.6\n/configure --prefix=/Bioinfo/Pipeline/SoftWare/python-3.11.6 ......\nmake && make install\n
\n

python3-confiigure-tkinter-yes

\n

对于 Python 3.10.x (及以下版本,如 Python-3.9.18),configure--with-tcltk-includes--with-tcltk-libs 的具体使用参考 https://bugs.python.org/issue21887

\n

tcltk-issue-21887-msg

\n

Python 2

\n

想要在 Python 2.7 安装 Tkinter,需要在编译过程中通过 --with-tcltk-includes--with-tcltk-libs 中指定 ActiveTcl 的头文件以及库所在路径。

\n

如果在执行编译安装过程中,出现无法找到 libXss.so.1 共享动态库报错:

\n
$ tar zvxf Python-2.7.15.tgz\n$ cd Python-2.7.15\n$ ./configure --prefix=/usr/local/software/python-2.7 --with-tcltk-includes=\'-I/usr/local/software/ActiveTcl-8.6/include\' --with-tcltk-libs=\'-L/usr/local/software/ActiveTcl-8.6/lib -ltcl8.6 -ltk8.6\' --enable-optimizations\n$ make\n\n......\n\nwarning: building with the bundled copy of libffi is deprecated on this platform.  It will not be distributed with Python 3.7\n*** WARNING: renaming "_tkinter" since importing it failed: libXss.so.1: cannot open shared object file: No such file or directory\n\nPython build finished successfully!\nThe necessary bits to build these optional modules were not found:\n_dbm                  _gdbm\nTo find the necessary bits, look in setup.py in detect_modules() for the module\'s name.\n\nThe following modules found by detect_modules() in setup.py, have been\nbuilt by the Makefile instead, as configured by the Setup files:\natexit                pwd                   time\n\nFollowing modules built successfully but were removed because they could not be imported:\n_tkinter\n\nrunning build_scripts\n\n......
\n

CentOS 下请参考以下解决方法:

\n
$ sudo yum install libXScrnSaver libXScrnSaver-devel\n
\n

调用 Tkinter

\n

Python 2/3 重新编译完后,执行一下下面的命令即可显示 Tk 的 ui 界面,以及相应的 Tcl/Tk 版本。

\n
python2 -m Tkinter   # python 2\npython3 -m tkinter   # python 3\n
\n

python2-m-Tkinter

\n

这时候,我们重新运行开头的 GUI 界面程序,可以看到中文已经正常显示:
\n

\n

参考资料

\n', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '1.3.5-Python'}]}, 'comments': {'nodes': []}}, {'title': '飞书文档初体验', 'number': 11, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/11', 'createdAt': '2023-10-24T07:57:52Z', 'lastEditedAt': '2023-12-01T02:24:27Z', 'updatedAt': '2024-01-04T05:44:25Z', 'body': '2023 年的 1024 程序员节前一天,语雀服务器崩溃长达 8 个小时的余温还没消,就迫不及待再去体验了一把飞书文档,说几点个人感受。\r\n\r\n\r\n\r\n![20231023-yuque](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/Gitbook/2023/20231023-yuque.png)\r\n\r\n- [如何看待语雀因网络故障导致用户无法正常访问文档?在线文档的可靠性还值得信任吗?](https://www.zhihu.com/question/627418678) - 知乎\r\n- [鉴于昨天的语雀,有啥推荐的笔记软件么](https://www.v2ex.com/t/984728) -V2EX\r\n\r\n\r\n首先,飞书文档[国内版本](https://www.feishu.cn/)和[国际版本](https://www.larksuite.com/)的区别可不是一般的大。\r\n\r\n![飞书文档国内版本](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/Gitbook/2023/feishu-cn-admin.png)\r\n\r\n![飞书文档国际版本](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/Gitbook/2023/larksuite-admin.png)\r\n\r\n第二,书写体验相当不错。\r\n\r\n第三,最然支持 Markdown 所见即所得的编辑模式,但没法查看单篇文档的 Markdown,这也是我最不满意的地方。\r\n\r\n第四,API 很强大,文档很丰富,但没找到怎么通过 API 获取 wiki 知识库内容的介绍!\r\n\r\n截止 2023.10.25 了解到飞书目前是没有 wiki 知识库内容的 API 接口,不清楚后面是否会有这方面的支持,且持续关注中。\r\n\r\n![飞书文档 wiki 知识库 API](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/feishu-wiki-api.png)\r\n\r\n事实上,飞书是支持 通过 API 接口获取 wiki 知识库内容的(上面截图中客服的回答并不准确),具体可以参考 [Feishu Pages](https://github.com/longbridgeapp/feishu-pages#feishu-pages) 实现 wiki 知识库的内容导出。\r\n\r\n第五,经历语雀宕机事件,不得不考虑多平台备份的问题,对于飞书文档目前没发现比较好的方法。\r\n\r\n经过了这个事件很多人都对在线文档产生了一些动摇,但总体来说在使用性和方便性上在线文档还是很有优势的,但值得注意的是不能把所有的鸡蛋都放到一个篮子 —— 备份很重要!**通用格式** 和 **数据可控** 或者可以成为一个评判的基础,那些过于封闭不支持导出(甚至是批量导出)的平台基本可以放弃了。\r\n', 'bodyText': '2023 年的 1024 程序员节前一天,语雀服务器崩溃长达 8 个小时的余温还没消,就迫不及待再去体验了一把飞书文档,说几点个人感受。\n\n\n\n如何看待语雀因网络故障导致用户无法正常访问文档?在线文档的可靠性还值得信任吗? - 知乎\n鉴于昨天的语雀,有啥推荐的笔记软件么 -V2EX\n\n首先,飞书文档国内版本和国际版本的区别可不是一般的大。\n\n\n第二,书写体验相当不错。\n第三,最然支持 Markdown 所见即所得的编辑模式,但没法查看单篇文档的 Markdown,这也是我最不满意的地方。\n第四,API 很强大,文档很丰富,但没找到怎么通过 API 获取 wiki 知识库内容的介绍!\n截止 2023.10.25 了解到飞书目前是没有 wiki 知识库内容的 API 接口,不清楚后面是否会有这方面的支持,且持续关注中。\n\n事实上,飞书是支持 通过 API 接口获取 wiki 知识库内容的(上面截图中客服的回答并不准确),具体可以参考 Feishu Pages 实现 wiki 知识库的内容导出。\n第五,经历语雀宕机事件,不得不考虑多平台备份的问题,对于飞书文档目前没发现比较好的方法。\n经过了这个事件很多人都对在线文档产生了一些动摇,但总体来说在使用性和方便性上在线文档还是很有优势的,但值得注意的是不能把所有的鸡蛋都放到一个篮子 —— 备份很重要!通用格式 和 数据可控 或者可以成为一个评判的基础,那些过于封闭不支持导出(甚至是批量导出)的平台基本可以放弃了。', 'bodyHTML': '

2023 年的 1024 程序员节前一天,语雀服务器崩溃长达 8 个小时的余温还没消,就迫不及待再去体验了一把飞书文档,说几点个人感受。

\n\n

20231023-yuque

\n\n

首先,飞书文档国内版本国际版本的区别可不是一般的大。

\n

飞书文档国内版本

\n

飞书文档国际版本

\n

第二,书写体验相当不错。

\n

第三,最然支持 Markdown 所见即所得的编辑模式,但没法查看单篇文档的 Markdown,这也是我最不满意的地方。

\n

第四,API 很强大,文档很丰富,但没找到怎么通过 API 获取 wiki 知识库内容的介绍!

\n

截止 2023.10.25 了解到飞书目前是没有 wiki 知识库内容的 API 接口,不清楚后面是否会有这方面的支持,且持续关注中。

\n

飞书文档 wiki 知识库 API

\n

事实上,飞书是支持 通过 API 接口获取 wiki 知识库内容的(上面截图中客服的回答并不准确),具体可以参考 Feishu Pages 实现 wiki 知识库的内容导出。

\n

第五,经历语雀宕机事件,不得不考虑多平台备份的问题,对于飞书文档目前没发现比较好的方法。

\n

经过了这个事件很多人都对在线文档产生了一些动摇,但总体来说在使用性和方便性上在线文档还是很有优势的,但值得注意的是不能把所有的鸡蛋都放到一个篮子 —— 备份很重要!通用格式数据可控 或者可以成为一个评判的基础,那些过于封闭不支持导出(甚至是批量导出)的平台基本可以放弃了。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'WebStack-Hugo | 一个静态响应式导航主题', 'number': 10, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/10', 'createdAt': '2023-10-23T08:25:32Z', 'lastEditedAt': '2024-11-05T01:44:19Z', 'updatedAt': '2024-11-05T01:44:19Z', 'body': '> Via:[我给自己做了一个导航网站](https://mp.weixin.qq.com/s/gVWGjxG9qd7qSyX3N8Zgag) | [BioIT爱好者](https://www.bioitee.com) \r\n\r\n
\r\n\r\n**📢 让更多人的人制作自己的导航网站。如果你觉得本主题对你有所帮助,欢迎请作者 [喝杯咖啡](https://kg.weiyan.cc/0000/img/donate.webp) >.<**\r\n\r\n## 主题开源地址 \r\n\r\n[**GitHub**](https://github.com/shenweiyan/WebStack-Hugo) | [**Gitee**](https://gitee.com/shenweiyan/WebStack-Hugo) | [**GitCode**](https://gitcode.com/shenweiyan/WebStack-Hugo)\r\n\r\n## 主题展示地址\r\n\r\n[**WebStack-Hugo 网址导航**](https://bioit.top/) | [**生信网址导航**](https://hao.bioitee.com/) \r\n\r\n## 为什么做这个网站\r\n\r\n之所以想着要给自己倒腾一个导航网站,主要有几个原因:\r\n\r\n- 购买了一个域名,且也备案成功了,总想折腾点跟它有关的事情;\r\n- 经常在公司、家里(有时候还有其他的临时场所)更换电脑,每次同步书签(或者登陆一些导航网站)需要各种登陆,麻烦。\r\n\r\n说干就干,从 [WebStack 的开源项目](https://github.com/WebStackPage/WebStackPage.github.io)开始,断断续续的折腾了好几天,终于把轮子造起来了。\r\n\r\n\r\n\r\n\r\nwebstack-apple\r\n\r\n## 跟其他导航网站有什么区别\r\n\r\n这是 Hugo 版 WebStack 主题。可以借助 Github/Gitee Pages 或者云平台直接托管部署,无需服务器。\r\n\r\n本项目是基于纯静态的网址导航网站 [webstack.cc](https://github.com/WebStackPage/WebStackPage.github.io) 制作的 [Hugo](https://gohugo.io/) 主题,其中部分代码参考了以下几个开源项目:\r\n\r\n- [https://github.com/WebStackPage/WebStackPage.github.io](https://github.com/WebStackPage/WebStackPage.github.io)\r\n- [https://github.com/liutongxu/liutongxu.github.io](https://github.com/WebStackPage/WebStackPage.github.io)\r\n- [https://github.com/iplaycode/webstack-hugo](https://github.com/iplaycode/webstack-hugo)\r\n\r\n总体说一下特点:\r\n\r\n- 采用了一直以来最喜欢的 hugo 部署方式,方便高效。\r\n- 主要的配置信息都集成到了 **config.toml**,一键完成各种自定义的配置。\r\n- 导航的各个信息都集成在 **data/webstack.yml** 文件中,方便后续增删改动。\r\n\r\n```yaml\r\n- taxonomy: 科研办公\r\n icon: fas fa-flask fa-lg\r\n list:\r\n - term: 生物信息\r\n links:\r\n - title: NCBI\r\n logo: n/ncbi.jpg\r\n url: https://www.ncbi.nlm.nih.gov/\r\n description: National Center for Biotechnology Information.\r\n - title: Bioconda\r\n logo: b/bioconda.jpg\r\n url: https://anaconda.org/bioconda/\r\n description: "Bioconda :: Anaconda.org."\r\n - term: 云服务器\r\n links:\r\n - title: 阿里云\r\n logo: a/aliyun.jpg\r\n url: https://www.aliyun.com/\r\n description: 上云就上阿里云。\r\n - title: 腾讯云\r\n logo: c/cloud-tencent.jpg\r\n url: https://cloud.tencent.com/\r\n description: 产业智变,云启未来。\r\n```\r\n\r\n- 做了手机电脑自适应以及夜间模式。\r\n- 增加了搜索功能,以及下拉的热词选项(基于百度 API)。\r\n- 增加了一言、和风天气的 API(和风天气 API 已经官方已经不再支持,目前还没到到替代)。\r\n\r\n## Windows 下安装部署\r\n\r\n本安装部署在 Windows 7 x64 上测试没问题,相关操作同样适用于 Windows 10,如有任何问题,欢迎留言或者微信与我联系。\r\n\r\n### 第一,下载 hugo\r\n\r\n下载链接:[https://github.com/gohugoio/hugo/releases](https://github.com/gohugoio/hugo/releases),在这里我们下载 [hugo_0.89.4_Windows-64bit.zip](https://github.com/gohugoio/hugo/releases/download/v0.89.4/hugo_0.89.4_Windows-64bit.zip)。\r\n\r\n![download-hugo-windows](https://kg.weiyan.cc/2023/11/download-hugo-windows.png)\r\n\r\n### 第二,解压\r\n\r\n我们把 [hugo_0.89.4_Windows-64bit.zip](https://github.com/gohugoio/hugo/releases/download/v0.89.4/hugo_0.89.4_Windows-64bit.zip) 下载到 **F:\\WebStack** 目录下,然后解压到当前文件夹。\r\n\r\n解压完成后,在该目录会多出 `hugo.exe`、`LICENSE`、`README.md` 三个文件:\r\n\r\n![unzip hugo_0.89.4_Windows-64bit](https://kg.weiyan.cc/2023/11/unzip-hugo-0.89.4-windows-64bit.png)\r\n\r\n### 第三,检测是否安装成功\r\n\r\n通过下面的方法,检测 `hugo` 是否安装成功。\r\n\r\n> **🏷️ 温馨提示:**\r\n> \r\n> Windows 命令运行窗口中可以使用 Tab 进行命令行补全,例如你当前目录下有一个 WebStack-Hugo 目录,你在命令行窗口中输入一个 w 后按下 Tab 键,命令行就会自动出现 WebStack-Hugo!\r\n> \r\n> 使用命令行补全,可以减少代码(或者文件名)的输入,方便快捷,又能减少错误!\r\n\r\n1. 在 Windows 中使用 **Win+R** 打开“**运行**”对话框,在对话框中输入“**cmd**”,点击确认。\r\n\r\n ![win-r-cmd](https://kg.weiyan.cc/2023/11/win-r-cmd.png)\r\n\r\n2. 在 Windows 运行窗口,先切换盘符到 **F** 盘,然后进入 `hugo` 的解压缩目录(**F:\\WebStack**),具体操作如下。\r\n\r\n - 在光标处输入 **F:**,然后按回车;\r\n\r\n ![cmd-change-dir](https://kg.weiyan.cc/2023/11/cmd-change-dir.png)\r\n\r\n - 我们就将盘符切换为 **F** 盘;\r\n\r\n ![cmd-f-dir](https://kg.weiyan.cc/2023/11/cmd-f-dir.png)\r\n\r\n - 接着输入 **cd WebStack**,回车,就进入了 **F:\\WebStack** 目录;使用 **ls** 可以看到当前目录下的文件。\r\n\r\n ![webstack-win-ls](https://kg.weiyan.cc/2023/11/webstack-win-ls.png)\r\n\r\n - 最后,输入 **hugo.exe version**,回车,如图所示,则代表安装成功。\r\n\r\n ![hugo-exe-version](https://kg.weiyan.cc/2023/11/hugo-exe-version.png)\r\n\r\n### 第四,下载 WebStack-Hugo\r\n\r\n浏览器打开 [https://github.com/shenweiyan/WebStack-Hugo](https://github.com/shenweiyan/WebStack-Hugo),点击 Code 下的 **"Download ZIP"**,把 **WebStack-hugo-main.zip** 下载到刚才 hugo 解压缩的目录(**F:\\WebStack**)。\r\n\r\n![webstack-download-zip](https://kg.weiyan.cc/2023/11/webstack-download-zip.png)\r\n\r\n![webstack-hugo-main-zip](https://kg.weiyan.cc/2023/11/webstack-hugo-main-zip.png)\r\n\r\n### 第五,解压和重命名\r\n\r\n把 **WebStack-Hugo-main.zip** 解压到当前目录。\r\n\r\n![webstack-hugo-main-unzip](https://kg.weiyan.cc/2023/11/webstack-hugo-main-unzip.png)\r\n![webstack-hugo-main-rename](https://kg.weiyan.cc/2023/11/webstack-hugo-main-rename.png)\r\n\r\n### 第六,安装主题\r\n\r\n首先,进入 **F:\\WebStack** 目录;\r\n\r\n然后,创建一个 **themes** 的文件夹;\r\n\r\n![create-themes-dir](https://kg.weiyan.cc/2023/11/create-themes-dir.png)\r\n\r\n接着,把解压后的 **WebStack-Hugo** 整个文件夹移动到 **themes** 中。\r\n\r\n![mv-webstack-hugo-to-themes](https://kg.weiyan.cc/2023/11/mv-webstack-hugo-to-themes.png)\r\n\r\n第四,将 `themes/WebStack-Hugo/exampleSite` 目录下的所有文件复制到 hugo 站点根目录(即 `F:\\WebStack`)。\r\n\r\n![cp-examplesite](https://kg.weiyan.cc/2023/11/cp-examplesite.png)\r\n\r\n### 第七,启动预览\r\n\r\n在刚才已经打开的 Windows 命令运行窗口中,使用下面的命令执行 **hugo server**,启动站点——Hugo 可以启动一个 Web 服务器,同时构建站点内容到内存中并在检测到文件更改后重新渲染,方便我们在开发环境实时预览对站点所做的更改。\r\n\r\n```shell\r\nhugo.exe server\r\n```\r\n\r\n![hugo-exe-server](https://kg.weiyan.cc/2023/11/hugo-exe-server.png)\r\n\r\n最后,在浏览器中打开 [**http://127.0.0.1:1313/**](http://127.0.0.1:1313/),即可看到生成的站点。\r\n\r\n![webstack-hugo-1313](https://kg.weiyan.cc/2023/11/webstack-hugo-1313.png)\r\n\r\n## Linux 下安装部署\r\n\r\n安装完本 WebStack-Hugo 主题后,将 exampleSite 目录下的文件复制到 hugo 站点根目录,根据需要把 config.toml 的一些信息改成自己的,导航的网址信息可通过 data 目录下 webstack.yml 修改。\r\n\r\n具体执行步骤如下:\r\n\r\n```bash\r\nmkdir /home/shenweiyan/mysite\r\ncd /home/shenweiyan/mysite\r\n\r\n# 安装 WebStack-Hugo 主题\r\ngit clone https://github.com/shenweiyan/WebStack-Hugo.git themes/WebStack-Hugo\r\n\r\n# 将 exampleSite 目录下的文件复制到 hugo 站点根目录\r\ncd /home/shenweiyan/mysite\r\ncp -r themes/WebStack-Hugo/exampleSite/* ./\r\n\r\n# 启动 hugo 站点\r\nhugo server\r\n# 如果你知道你的公网 ip, 如下面的 132.76.230.31, 可以使用下面的方式执行 hugo server\r\nhugo server --baseUrl=132.76.230.31 --bind=0.0.0.0\r\n```\r\n\r\n也可以参考 [@jetsung](https://github.com/jetsung) 在 [pull 15](https://github.com/shenweiyan/WebStack-Hugo/pull/15) 所用的方法安装部署:\r\n\r\n```bash\r\n# 创建项目\r\nmkdir navsites\r\ncd $_\r\n\r\n# 初始化项目\r\ngit init\r\n\r\n# 将 WebStack-Hugo 源下载到 themes/WebStack-Hugo 文件夹\r\ngit submodule add https://github.com/shenweiyan/WebStack-Hugo.git themes/WebStack-Hugo\r\ncp -r themes/WebStack-Hugo/exampleSite/* ./\r\n\r\n# 安装 hugo\r\ngo install github.com/gohugoio/hugo@latest\r\n\r\n# 本地测试\r\nhugo server\r\n\r\n# 生成 docs 文件夹,将并静态内容生成至此处\r\nhugo -D\r\n```\r\n\r\n## 导出 HTML 静态资源\r\n\r\nWindows/Linux 下执行的 **hugo server** 命令将会通过热加载的方式临时启动一个 Hugo 服务器(Hugo 可以启动一个 Web 服务器,同时构建站点内容到内存中并在检测到文件更改后重新渲染,方便我们在开发环境实时预览对站点所做的更改),这个时候我们打开浏览器 [http://127.0.0.1:1313/](http://127.0.0.1:1313/),就可以看到我们站点的样子了。\r\n\r\n如果我们想要把我们的站点部署到 GitHub/Gitee Pages(或者本地的服务器),我们可以:\r\n\r\n### 1. 生成静态页面内容\r\n\r\n可以通过下面的命令,生成(构建)静态页面内容。\r\n\r\n```python\r\nhugo -D 或者 hugo --minify\r\n```\r\n\r\n这个命令会默认在 **`public/`** 目录中生成您的网站,当然您可以通过改变站点配置中的 **`publishDir`** 选项来配置这个输出目录。\r\n\r\n> **🏷️ Hugo 小知识 - 草案、未来和过期内容**\r\n> \r\n> Hugo 允许您在网站内容的前言设定中设置文档的`draft`,`publishdate`甚至`expirydate`字段。默认情况下,Hugo 不会发布下面内容:\r\n>\r\n> 1. `publishdate` 发布日期值设定在未来的内容;\r\n> 2. `draft:true` 草案状态设置为真的内容;\r\n> 3. `expirydate` 过期日期值设置为过去某事件的内容。\r\n>\r\n> 这三个可以在本地开发和部署编译时通过对`hugo`和`hugo server`分别添加如下参数来重新设定,或者在配置文件中设定对应(不包含`--`)域的 boolean 值:\r\n>\r\n> 1. -F, --buildFuture include content with publishdate in the future\r\n> 2. -D, --buildDrafts include content marked as draft\r\n> 3. -E, --buildExpired include expired content\r\n\r\n### 2. 部署站点\r\n\r\n把生成的 `public/` 静态内容目录上传到 GitHub,开启 GitHub/Gitee Pages,并且绑定 cname 域名即可。\r\n\r\n## 使用说明与技巧\r\n\r\n这是一个开源的公益项目,你可以拿来制作自己的网址导航,也可以做与导航无关的网站。\r\n\r\n### 左导航栏图标\r\n\r\n左侧、顶部导航栏图标用的都是 **Font Awesome** 图标库 **v5** 版本 **Free** 的图标。链接如下:\r\n\r\n🔗 [https://fontawesome.com/v5/search?o=r&m=free](https://fontawesome.com/v5/search?o=r&m=free)\r\n\r\n![fontawesome-v5-free](https://kg.weiyan.cc/2023/11/fontawesome-v5-free.png)\r\n\r\n### 调整头部搜索栏\r\n\r\n头部搜索栏的默认位置可以通过下面的方法进行修改。\r\n\r\n1. 直接修改 **layouts/partials/content_search.html**,调整对应部分的位置。\r\n2. 调整默认的搜索(即点击"常用/搜索/工具 ...." 时下指箭头的指向),把对应的 id 添加到对应的 label 里面。\r\n\r\n![set-default-search-bing](https://kg.weiyan.cc/2023/11/set-default-search-bing.png)\r\n![view-default-search-bing](https://kg.weiyan.cc/2023/11/view-default-search-bing.png)\r\n\r\n### 自定义头部导航\r\n\r\n[WebStack-Hugo](https://github.com/shenweiyan/WebStack-Hugo) 把头部的导航菜单的各个信息集成在了 **data/header.yml** 文件中,每个人可以根据自己的需要调整。\r\n\r\n```yaml\r\n- item: 首页\r\n icon: fa fa-home\r\n link: "./"\r\n\r\n- item: 作者\r\n icon: fa fa-book\r\n link: https://www.yuque.com/shenweiyan\r\n\r\n- item: 配置\r\n icon: fa fa-cog\r\n link: ""\r\n list:\r\n - name: 源码\r\n url: "#"\r\n - name: 图标\r\n url: "#"\r\n```\r\n\r\n### 获取网站图标\r\n\r\n[Bio & IT 网址导航](https://nav.bioitee.com/)默认使用的是个人收集的网站图标,主要是查看网站源码、百度、谷歌等途径把对应导航的图标下载下来,这个方法比较原始繁琐,适合导航不是很多的情况。\r\n\r\n#### 一为\r\n\r\n你也可以使用一为提供的的 [Favicon](https://www.iowen.cn/tag/favicon/) 图标 [API](https://www.iowen.cn/tag/api/):[获取网站 Favicon - 免费 API 数据接口调用服务平台](https://api.iowen.cn/doc/favicon.html)。\r\n\r\n**使用方法:**\r\n\r\n1. 获取 Favicon 图标\r\n```\r\nhttps://api.iowen.cn/favicon/www.iowen.cn.png\r\n```\r\n\r\n2. 刷新缓存\r\n```\r\nhttps://api.iowen.cn/favicon/www.iowen.cn.png?refresh=true\r\n```\r\n\r\n3. 将上方代码中的 `www.iowen.cn` 替换为你需要获取的网址域名。\r\n\r\n#### Favicon.im\r\n\r\n除了一为的 API,你也可以使用 来在网页中插入其他网站的 Favicon 图片,可以放大显示。\r\n\r\n![favicon-im](https://kg.weiyan.cc/2024/08/favicon-im.webp)\r\n\r\n#### Favicon Extractor\r\n\r\n类似网站 [Favicon Downloader](https://www.faviconextractor.com/),代码[开源](https://github.com/seadfeng/favicon-downloader)。\r\n\r\n![favicon-extractor](https://kg.weiyan.cc/2024/08/favicon-extractor.webp)\r\n\r\n\r\n## 已知问题\r\n\r\n1. 日间模式与夜间模式切换时候,头部搜索栏的背景图片切换不够流畅(个人的 js 知识有限,在 footer.html 做了一些简单的调整来实现),如果你有更好的想法,欢迎 PR 或者交流。\r\n\r\n## 感谢墙\r\n\r\n本主题的部分代码参考了以下几个开源项目,特此感谢。\r\n\r\n- [WebStackPage/WebStackPage.github.io](https://github.com/WebStackPage/WebStackPage.github.io)\r\n- [liutongxu/liutongxu.github.io](https://github.com/liutongxu/liutongxu.github.io)\r\n- [iplaycode/webstack-hugo](https://github.com/iplaycode/webstack-hugo)\r\n\r\n感谢 [WebStack](https://github.com/WebStackPage/WebStackPage.github.io) 的作者 [Viggo](https://twitter.com/decohack) 的肯定和[推广宣传](https://twitter.com/decohack/status/1569188705478516738)。\r\n\r\n![twitter-decohack-webstack-hugo](https://kg.weiyan.cc/2023/11/twitter-decohack-webstack-hugo.png)\r\n\r\n感谢以下所有朋友对本主题所做出的贡献。 \r\n**[@yanbeiyinhanghang](https://github.com/yinhanghang)** \r\n**[@jetsung](https://github.com/jetsung)** \r\n\r\n## 赞赏\r\n\r\n如果你觉得本项目对你有所帮助,欢迎请作者喝杯热咖啡 >.< \r\n\r\n![donate-wecaht-aliapy](https://kg.weiyan.cc/0000/img/donate.webp)\r\n\r\n## 反馈与交流\r\n\r\n最后,最重要的,秉承 WebStack 的宗旨,这是一个开源的公益项目,你可以拿来制作自己的网址导航,也可以做与导航无关的网站。\r\n\r\nWebStack 有非常多的魔改版本,这是其中一个。\r\n\r\n**如果你对本主题进行了一些个性化调整,欢迎在本项目中 **[**issues**](https://github.com/shenweiyan/WebStack-Hugo/issues)** 中一起分享交流!**\r\n\r\n**如果参考本主题构建了属于你自己的网址导航,欢迎在本评论区(或源码 **[**issues**](https://github.com/shenweiyan/WebStack-Hugo/issues)** 区)留下你网站的访问链接 >.<**\r\n', 'bodyText': 'Via:我给自己做了一个导航网站 | BioIT爱好者\n\n\n📢 让更多人的人制作自己的导航网站。如果你觉得本主题对你有所帮助,欢迎请作者 喝杯咖啡 >.<\n主题开源地址\nGitHub | Gitee | GitCode\n主题展示地址\nWebStack-Hugo 网址导航 | 生信网址导航\n为什么做这个网站\n之所以想着要给自己倒腾一个导航网站,主要有几个原因:\n\n购买了一个域名,且也备案成功了,总想折腾点跟它有关的事情;\n经常在公司、家里(有时候还有其他的临时场所)更换电脑,每次同步书签(或者登陆一些导航网站)需要各种登陆,麻烦。\n\n说干就干,从 WebStack 的开源项目开始,断断续续的折腾了好几天,终于把轮子造起来了。\n\n\n\n\n跟其他导航网站有什么区别\n这是 Hugo 版 WebStack 主题。可以借助 Github/Gitee Pages 或者云平台直接托管部署,无需服务器。\n本项目是基于纯静态的网址导航网站 webstack.cc 制作的 Hugo 主题,其中部分代码参考了以下几个开源项目:\n\nhttps://github.com/WebStackPage/WebStackPage.github.io\nhttps://github.com/liutongxu/liutongxu.github.io\nhttps://github.com/iplaycode/webstack-hugo\n\n总体说一下特点:\n\n采用了一直以来最喜欢的 hugo 部署方式,方便高效。\n主要的配置信息都集成到了 config.toml,一键完成各种自定义的配置。\n导航的各个信息都集成在 data/webstack.yml 文件中,方便后续增删改动。\n\n- taxonomy: 科研办公\n icon: fas fa-flask fa-lg\n list:\n - term: 生物信息\n links:\n - title: NCBI\n logo: n/ncbi.jpg\n url: https://www.ncbi.nlm.nih.gov/\n description: National Center for Biotechnology Information.\n - title: Bioconda\n logo: b/bioconda.jpg\n url: https://anaconda.org/bioconda/\n description: "Bioconda :: Anaconda.org."\n - term: 云服务器\n links:\n - title: 阿里云\n logo: a/aliyun.jpg\n url: https://www.aliyun.com/\n description: 上云就上阿里云。\n - title: 腾讯云\n logo: c/cloud-tencent.jpg\n url: https://cloud.tencent.com/\n description: 产业智变,云启未来。\n\n做了手机电脑自适应以及夜间模式。\n增加了搜索功能,以及下拉的热词选项(基于百度 API)。\n增加了一言、和风天气的 API(和风天气 API 已经官方已经不再支持,目前还没到到替代)。\n\nWindows 下安装部署\n本安装部署在 Windows 7 x64 上测试没问题,相关操作同样适用于 Windows 10,如有任何问题,欢迎留言或者微信与我联系。\n第一,下载 hugo\n下载链接:https://github.com/gohugoio/hugo/releases,在这里我们下载 hugo_0.89.4_Windows-64bit.zip。\n\n第二,解压\n我们把 hugo_0.89.4_Windows-64bit.zip 下载到 F:\\WebStack 目录下,然后解压到当前文件夹。\n解压完成后,在该目录会多出 hugo.exe、LICENSE、README.md 三个文件:\n\n第三,检测是否安装成功\n通过下面的方法,检测 hugo 是否安装成功。\n\n🏷️ 温馨提示:\nWindows 命令运行窗口中可以使用 Tab 进行命令行补全,例如你当前目录下有一个 WebStack-Hugo 目录,你在命令行窗口中输入一个 w 后按下 Tab 键,命令行就会自动出现 WebStack-Hugo!\n使用命令行补全,可以减少代码(或者文件名)的输入,方便快捷,又能减少错误!\n\n\n\n在 Windows 中使用 Win+R 打开“运行”对话框,在对话框中输入“cmd”,点击确认。\n\n\n\n在 Windows 运行窗口,先切换盘符到 F 盘,然后进入 hugo 的解压缩目录(F:\\WebStack),具体操作如下。\n\n\n在光标处输入 F:,然后按回车;\n\n\n\n我们就将盘符切换为 F 盘;\n\n\n\n接着输入 cd WebStack,回车,就进入了 F:\\WebStack 目录;使用 ls 可以看到当前目录下的文件。\n\n\n\n最后,输入 hugo.exe version,回车,如图所示,则代表安装成功。\n\n\n\n\n\n第四,下载 WebStack-Hugo\n浏览器打开 https://github.com/shenweiyan/WebStack-Hugo,点击 Code 下的 "Download ZIP",把 WebStack-hugo-main.zip 下载到刚才 hugo 解压缩的目录(F:\\WebStack)。\n\n\n第五,解压和重命名\n把 WebStack-Hugo-main.zip 解压到当前目录。\n\n\n第六,安装主题\n首先,进入 F:\\WebStack 目录;\n然后,创建一个 themes 的文件夹;\n\n接着,把解压后的 WebStack-Hugo 整个文件夹移动到 themes 中。\n\n第四,将 themes/WebStack-Hugo/exampleSite 目录下的所有文件复制到 hugo 站点根目录(即 F:\\WebStack)。\n\n第七,启动预览\n在刚才已经打开的 Windows 命令运行窗口中,使用下面的命令执行 hugo server,启动站点——Hugo 可以启动一个 Web 服务器,同时构建站点内容到内存中并在检测到文件更改后重新渲染,方便我们在开发环境实时预览对站点所做的更改。\nhugo.exe server\n\n最后,在浏览器中打开 http://127.0.0.1:1313/,即可看到生成的站点。\n\nLinux 下安装部署\n安装完本 WebStack-Hugo 主题后,将 exampleSite 目录下的文件复制到 hugo 站点根目录,根据需要把 config.toml 的一些信息改成自己的,导航的网址信息可通过 data 目录下 webstack.yml 修改。\n具体执行步骤如下:\nmkdir /home/shenweiyan/mysite\ncd /home/shenweiyan/mysite\n\n# 安装 WebStack-Hugo 主题\ngit clone https://github.com/shenweiyan/WebStack-Hugo.git themes/WebStack-Hugo\n\n# 将 exampleSite 目录下的文件复制到 hugo 站点根目录\ncd /home/shenweiyan/mysite\ncp -r themes/WebStack-Hugo/exampleSite/* ./\n\n# 启动 hugo 站点\nhugo server\n# 如果你知道你的公网 ip, 如下面的 132.76.230.31, 可以使用下面的方式执行 hugo server\nhugo server --baseUrl=132.76.230.31 --bind=0.0.0.0\n也可以参考 @jetsung 在 pull 15 所用的方法安装部署:\n# 创建项目\nmkdir navsites\ncd $_\n\n# 初始化项目\ngit init\n\n# 将 WebStack-Hugo 源下载到 themes/WebStack-Hugo 文件夹\ngit submodule add https://github.com/shenweiyan/WebStack-Hugo.git themes/WebStack-Hugo\ncp -r themes/WebStack-Hugo/exampleSite/* ./\n\n# 安装 hugo\ngo install github.com/gohugoio/hugo@latest\n\n# 本地测试\nhugo server\n\n# 生成 docs 文件夹,将并静态内容生成至此处\nhugo -D\n导出 HTML 静态资源\nWindows/Linux 下执行的 hugo server 命令将会通过热加载的方式临时启动一个 Hugo 服务器(Hugo 可以启动一个 Web 服务器,同时构建站点内容到内存中并在检测到文件更改后重新渲染,方便我们在开发环境实时预览对站点所做的更改),这个时候我们打开浏览器 http://127.0.0.1:1313/,就可以看到我们站点的样子了。\n如果我们想要把我们的站点部署到 GitHub/Gitee Pages(或者本地的服务器),我们可以:\n1. 生成静态页面内容\n可以通过下面的命令,生成(构建)静态页面内容。\nhugo -D 或者 hugo --minify\n这个命令会默认在 public/ 目录中生成您的网站,当然您可以通过改变站点配置中的 publishDir 选项来配置这个输出目录。\n\n🏷️ Hugo 小知识 - 草案、未来和过期内容\nHugo 允许您在网站内容的前言设定中设置文档的draft,publishdate甚至expirydate字段。默认情况下,Hugo 不会发布下面内容:\n\npublishdate 发布日期值设定在未来的内容;\ndraft:true 草案状态设置为真的内容;\nexpirydate 过期日期值设置为过去某事件的内容。\n\n这三个可以在本地开发和部署编译时通过对hugo和hugo server分别添加如下参数来重新设定,或者在配置文件中设定对应(不包含--)域的 boolean 值:\n\n-F, --buildFuture include content with publishdate in the future\n-D, --buildDrafts include content marked as draft\n-E, --buildExpired include expired content\n\n\n2. 部署站点\n把生成的 public/ 静态内容目录上传到 GitHub,开启 GitHub/Gitee Pages,并且绑定 cname 域名即可。\n使用说明与技巧\n这是一个开源的公益项目,你可以拿来制作自己的网址导航,也可以做与导航无关的网站。\n左导航栏图标\n左侧、顶部导航栏图标用的都是 Font Awesome 图标库 v5 版本 Free 的图标。链接如下:\n🔗 https://fontawesome.com/v5/search?o=r&m=free\n\n调整头部搜索栏\n头部搜索栏的默认位置可以通过下面的方法进行修改。\n\n直接修改 layouts/partials/content_search.html,调整对应部分的位置。\n调整默认的搜索(即点击"常用/搜索/工具 ...." 时下指箭头的指向),把对应的 id 添加到对应的 label 里面。\n\n\n\n自定义头部导航\nWebStack-Hugo 把头部的导航菜单的各个信息集成在了 data/header.yml 文件中,每个人可以根据自己的需要调整。\n- item: 首页\n icon: fa fa-home\n link: "./"\n\n- item: 作者\n icon: fa fa-book\n link: https://www.yuque.com/shenweiyan\n\n- item: 配置\n icon: fa fa-cog\n link: ""\n list:\n - name: 源码\n url: "#"\n - name: 图标\n url: "#"\n获取网站图标\nBio & IT 网址导航默认使用的是个人收集的网站图标,主要是查看网站源码、百度、谷歌等途径把对应导航的图标下载下来,这个方法比较原始繁琐,适合导航不是很多的情况。\n一为\n你也可以使用一为提供的的 Favicon 图标 API:获取网站 Favicon - 免费 API 数据接口调用服务平台。\n使用方法:\n\n获取 Favicon 图标\n\nhttps://api.iowen.cn/favicon/www.iowen.cn.png\n\n\n刷新缓存\n\nhttps://api.iowen.cn/favicon/www.iowen.cn.png?refresh=true\n\n\n将上方代码中的 www.iowen.cn 替换为你需要获取的网址域名。\n\nFavicon.im\n除了一为的 API,你也可以使用 https://favicon.im/ 来在网页中插入其他网站的 Favicon 图片,可以放大显示。\n\nFavicon Extractor\n类似网站 Favicon Downloader,代码开源。\n\n已知问题\n\n日间模式与夜间模式切换时候,头部搜索栏的背景图片切换不够流畅(个人的 js 知识有限,在 footer.html 做了一些简单的调整来实现),如果你有更好的想法,欢迎 PR 或者交流。\n\n感谢墙\n本主题的部分代码参考了以下几个开源项目,特此感谢。\n\nWebStackPage/WebStackPage.github.io\nliutongxu/liutongxu.github.io\niplaycode/webstack-hugo\n\n感谢 WebStack 的作者 Viggo 的肯定和推广宣传。\n\n感谢以下所有朋友对本主题所做出的贡献。\n@yanbeiyinhanghang\n@jetsung\n赞赏\n如果你觉得本项目对你有所帮助,欢迎请作者喝杯热咖啡 >.<\n\n反馈与交流\n最后,最重要的,秉承 WebStack 的宗旨,这是一个开源的公益项目,你可以拿来制作自己的网址导航,也可以做与导航无关的网站。\nWebStack 有非常多的魔改版本,这是其中一个。\n如果你对本主题进行了一些个性化调整,欢迎在本项目中 issues 中一起分享交流!\n如果参考本主题构建了属于你自己的网址导航,欢迎在本评论区(或源码 issues 区)留下你网站的访问链接 >.<', 'bodyHTML': '
\n

Via:我给自己做了一个导航网站 | BioIT爱好者

\n
\n
\n

📢 让更多人的人制作自己的导航网站。如果你觉得本主题对你有所帮助,欢迎请作者 喝杯咖啡 >.<

\n

主题开源地址

\n

GitHub | Gitee | GitCode

\n

主题展示地址

\n

WebStack-Hugo 网址导航 | 生信网址导航

\n

为什么做这个网站

\n

之所以想着要给自己倒腾一个导航网站,主要有几个原因:

\n
    \n
  • 购买了一个域名,且也备案成功了,总想折腾点跟它有关的事情;
  • \n
  • 经常在公司、家里(有时候还有其他的临时场所)更换电脑,每次同步书签(或者登陆一些导航网站)需要各种登陆,麻烦。
  • \n
\n

说干就干,从 WebStack 的开源项目开始,断断续续的折腾了好几天,终于把轮子造起来了。

\n

\n

\n

\n

webstack-apple

\n

跟其他导航网站有什么区别

\n

这是 Hugo 版 WebStack 主题。可以借助 Github/Gitee Pages 或者云平台直接托管部署,无需服务器。

\n

本项目是基于纯静态的网址导航网站 webstack.cc 制作的 Hugo 主题,其中部分代码参考了以下几个开源项目:

\n\n

总体说一下特点:

\n
    \n
  • 采用了一直以来最喜欢的 hugo 部署方式,方便高效。
  • \n
  • 主要的配置信息都集成到了 config.toml,一键完成各种自定义的配置。
  • \n
  • 导航的各个信息都集成在 data/webstack.yml 文件中,方便后续增删改动。
  • \n
\n
- taxonomy: 科研办公\n  icon: fas fa-flask fa-lg\n  list:\n    - term: 生物信息\n      links:\n        - title: NCBI\n          logo: n/ncbi.jpg\n          url: https://www.ncbi.nlm.nih.gov/\n          description: National Center for Biotechnology Information.\n        - title: Bioconda\n          logo: b/bioconda.jpg\n          url: https://anaconda.org/bioconda/\n          description: "Bioconda :: Anaconda.org."\n    - term: 云服务器\n      links:\n        - title: 阿里云\n          logo: a/aliyun.jpg\n          url: https://www.aliyun.com/\n          description: 上云就上阿里云。\n        - title: 腾讯云\n          logo: c/cloud-tencent.jpg\n          url: https://cloud.tencent.com/\n          description: 产业智变,云启未来。
\n
    \n
  • 做了手机电脑自适应以及夜间模式。
  • \n
  • 增加了搜索功能,以及下拉的热词选项(基于百度 API)。
  • \n
  • 增加了一言、和风天气的 API(和风天气 API 已经官方已经不再支持,目前还没到到替代)。
  • \n
\n

Windows 下安装部署

\n

本安装部署在 Windows 7 x64 上测试没问题,相关操作同样适用于 Windows 10,如有任何问题,欢迎留言或者微信与我联系。

\n

第一,下载 hugo

\n

下载链接:https://github.com/gohugoio/hugo/releases,在这里我们下载 hugo_0.89.4_Windows-64bit.zip

\n

download-hugo-windows

\n

第二,解压

\n

我们把 hugo_0.89.4_Windows-64bit.zip 下载到 F:\\WebStack 目录下,然后解压到当前文件夹。

\n

解压完成后,在该目录会多出 hugo.exeLICENSEREADME.md 三个文件:

\n

unzip hugo_0.89.4_Windows-64bit

\n

第三,检测是否安装成功

\n

通过下面的方法,检测 hugo 是否安装成功。

\n
\n

🏷️ 温馨提示:

\n

Windows 命令运行窗口中可以使用 Tab 进行命令行补全,例如你当前目录下有一个 WebStack-Hugo 目录,你在命令行窗口中输入一个 w 后按下 Tab 键,命令行就会自动出现 WebStack-Hugo!

\n

使用命令行补全,可以减少代码(或者文件名)的输入,方便快捷,又能减少错误!

\n
\n
    \n
  1. \n

    在 Windows 中使用 Win+R 打开“运行”对话框,在对话框中输入“cmd”,点击确认。

    \n

    win-r-cmd

    \n
  2. \n
  3. \n

    在 Windows 运行窗口,先切换盘符到 F 盘,然后进入 hugo 的解压缩目录(F:\\WebStack),具体操作如下。

    \n
      \n
    • \n

      在光标处输入 F:,然后按回车;

      \n

      cmd-change-dir

      \n
    • \n
    • \n

      我们就将盘符切换为 F 盘;

      \n

      cmd-f-dir

      \n
    • \n
    • \n

      接着输入 cd WebStack,回车,就进入了 F:\\WebStack 目录;使用 ls 可以看到当前目录下的文件。

      \n

      webstack-win-ls

      \n
    • \n
    • \n

      最后,输入 hugo.exe version,回车,如图所示,则代表安装成功。

      \n

      hugo-exe-version

      \n
    • \n
    \n
  4. \n
\n

第四,下载 WebStack-Hugo

\n

浏览器打开 https://github.com/shenweiyan/WebStack-Hugo,点击 Code 下的 "Download ZIP",把 WebStack-hugo-main.zip 下载到刚才 hugo 解压缩的目录(F:\\WebStack)。

\n

webstack-download-zip

\n

webstack-hugo-main-zip

\n

第五,解压和重命名

\n

WebStack-Hugo-main.zip 解压到当前目录。

\n

webstack-hugo-main-unzip
\nwebstack-hugo-main-rename

\n

第六,安装主题

\n

首先,进入 F:\\WebStack 目录;

\n

然后,创建一个 themes 的文件夹;

\n

create-themes-dir

\n

接着,把解压后的 WebStack-Hugo 整个文件夹移动到 themes 中。

\n

mv-webstack-hugo-to-themes

\n

第四,将 themes/WebStack-Hugo/exampleSite 目录下的所有文件复制到 hugo 站点根目录(即 F:\\WebStack)。

\n

cp-examplesite

\n

第七,启动预览

\n

在刚才已经打开的 Windows 命令运行窗口中,使用下面的命令执行 hugo server,启动站点——Hugo 可以启动一个 Web 服务器,同时构建站点内容到内存中并在检测到文件更改后重新渲染,方便我们在开发环境实时预览对站点所做的更改。

\n
hugo.exe server
\n

hugo-exe-server

\n

最后,在浏览器中打开 http://127.0.0.1:1313/,即可看到生成的站点。

\n

webstack-hugo-1313

\n

Linux 下安装部署

\n

安装完本 WebStack-Hugo 主题后,将 exampleSite 目录下的文件复制到 hugo 站点根目录,根据需要把 config.toml 的一些信息改成自己的,导航的网址信息可通过 data 目录下 webstack.yml 修改。

\n

具体执行步骤如下:

\n
mkdir /home/shenweiyan/mysite\ncd /home/shenweiyan/mysite\n\n# 安装 WebStack-Hugo 主题\ngit clone https://github.com/shenweiyan/WebStack-Hugo.git themes/WebStack-Hugo\n\n# 将 exampleSite 目录下的文件复制到 hugo 站点根目录\ncd /home/shenweiyan/mysite\ncp -r themes/WebStack-Hugo/exampleSite/* ./\n\n# 启动 hugo 站点\nhugo server\n# 如果你知道你的公网 ip, 如下面的 132.76.230.31, 可以使用下面的方式执行 hugo server\nhugo server --baseUrl=132.76.230.31 --bind=0.0.0.0
\n

也可以参考 @jetsungpull 15 所用的方法安装部署:

\n
# 创建项目\nmkdir navsites\ncd $_\n\n# 初始化项目\ngit init\n\n# 将 WebStack-Hugo 源下载到 themes/WebStack-Hugo 文件夹\ngit submodule add https://github.com/shenweiyan/WebStack-Hugo.git themes/WebStack-Hugo\ncp -r themes/WebStack-Hugo/exampleSite/* ./\n\n# 安装 hugo\ngo install github.com/gohugoio/hugo@latest\n\n# 本地测试\nhugo server\n\n# 生成 docs 文件夹,将并静态内容生成至此处\nhugo -D
\n

导出 HTML 静态资源

\n

Windows/Linux 下执行的 hugo server 命令将会通过热加载的方式临时启动一个 Hugo 服务器(Hugo 可以启动一个 Web 服务器,同时构建站点内容到内存中并在检测到文件更改后重新渲染,方便我们在开发环境实时预览对站点所做的更改),这个时候我们打开浏览器 http://127.0.0.1:1313/,就可以看到我们站点的样子了。

\n

如果我们想要把我们的站点部署到 GitHub/Gitee Pages(或者本地的服务器),我们可以:

\n

1. 生成静态页面内容

\n

可以通过下面的命令,生成(构建)静态页面内容。

\n
hugo -D 或者 hugo --minify
\n

这个命令会默认在 public/ 目录中生成您的网站,当然您可以通过改变站点配置中的 publishDir 选项来配置这个输出目录。

\n
\n

🏷️ Hugo 小知识 - 草案、未来和过期内容

\n

Hugo 允许您在网站内容的前言设定中设置文档的draftpublishdate甚至expirydate字段。默认情况下,Hugo 不会发布下面内容:

\n
    \n
  1. publishdate 发布日期值设定在未来的内容;
  2. \n
  3. draft:true 草案状态设置为真的内容;
  4. \n
  5. expirydate 过期日期值设置为过去某事件的内容。
  6. \n
\n

这三个可以在本地开发和部署编译时通过对hugohugo server分别添加如下参数来重新设定,或者在配置文件中设定对应(不包含--)域的 boolean 值:

\n
    \n
  1. -F, --buildFuture include content with publishdate in the future
  2. \n
  3. -D, --buildDrafts include content marked as draft
  4. \n
  5. -E, --buildExpired include expired content
  6. \n
\n
\n

2. 部署站点

\n

把生成的 public/ 静态内容目录上传到 GitHub,开启 GitHub/Gitee Pages,并且绑定 cname 域名即可。

\n

使用说明与技巧

\n

这是一个开源的公益项目,你可以拿来制作自己的网址导航,也可以做与导航无关的网站。

\n

左导航栏图标

\n

左侧、顶部导航栏图标用的都是 Font Awesome 图标库 v5 版本 Free 的图标。链接如下:

\n

🔗 https://fontawesome.com/v5/search?o=r&m=free

\n

fontawesome-v5-free

\n

调整头部搜索栏

\n

头部搜索栏的默认位置可以通过下面的方法进行修改。

\n
    \n
  1. 直接修改 layouts/partials/content_search.html,调整对应部分的位置。
  2. \n
  3. 调整默认的搜索(即点击"常用/搜索/工具 ...." 时下指箭头的指向),把对应的 id 添加到对应的 label 里面。
  4. \n
\n

set-default-search-bing
\nview-default-search-bing

\n

自定义头部导航

\n

WebStack-Hugo 把头部的导航菜单的各个信息集成在了 data/header.yml 文件中,每个人可以根据自己的需要调整。

\n
- item: 首页\n  icon: fa fa-home\n  link: "./"\n\n- item: 作者\n  icon: fa fa-book\n  link: https://www.yuque.com/shenweiyan\n\n- item: 配置\n  icon: fa fa-cog\n  link: ""\n  list:\n    - name: 源码\n      url: "#"\n    - name: 图标\n      url: "#"
\n

获取网站图标

\n

Bio & IT 网址导航默认使用的是个人收集的网站图标,主要是查看网站源码、百度、谷歌等途径把对应导航的图标下载下来,这个方法比较原始繁琐,适合导航不是很多的情况。

\n

一为

\n

你也可以使用一为提供的的 Favicon 图标 API获取网站 Favicon - 免费 API 数据接口调用服务平台

\n

使用方法:

\n
    \n
  1. 获取 Favicon 图标
  2. \n
\n
https://api.iowen.cn/favicon/www.iowen.cn.png\n
\n
    \n
  1. 刷新缓存
  2. \n
\n
https://api.iowen.cn/favicon/www.iowen.cn.png?refresh=true\n
\n
    \n
  1. 将上方代码中的 www.iowen.cn 替换为你需要获取的网址域名。
  2. \n
\n

Favicon.im

\n

除了一为的 API,你也可以使用 https://favicon.im/ 来在网页中插入其他网站的 Favicon 图片,可以放大显示。

\n

favicon-im

\n

Favicon Extractor

\n

类似网站 Favicon Downloader,代码开源

\n

favicon-extractor

\n

已知问题

\n
    \n
  1. 日间模式与夜间模式切换时候,头部搜索栏的背景图片切换不够流畅(个人的 js 知识有限,在 footer.html 做了一些简单的调整来实现),如果你有更好的想法,欢迎 PR 或者交流。
  2. \n
\n

感谢墙

\n

本主题的部分代码参考了以下几个开源项目,特此感谢。

\n\n

感谢 WebStack 的作者 Viggo 的肯定和推广宣传

\n

twitter-decohack-webstack-hugo

\n

感谢以下所有朋友对本主题所做出的贡献。
\n@yanbeiyinhanghang
\n@jetsung

\n

赞赏

\n

如果你觉得本项目对你有所帮助,欢迎请作者喝杯热咖啡 >.<

\n

donate-wecaht-aliapy

\n

反馈与交流

\n

最后,最重要的,秉承 WebStack 的宗旨,这是一个开源的公益项目,你可以拿来制作自己的网址导航,也可以做与导航无关的网站。

\n

WebStack 有非常多的魔改版本,这是其中一个。

\n

如果你对本主题进行了一些个性化调整,欢迎在本项目中 issues 中一起分享交流!

\n

如果参考本主题构建了属于你自己的网址导航,欢迎在本评论区(或源码 issues 区)留下你网站的访问链接 >.<

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '语雀'}, {'name': '1.3.25-静态网站'}]}, 'comments': {'nodes': [{'body': 'Built in 35 ms\r\nEnvironment: "development"\r\nServing pages from memory\r\nRunning in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender\r\nWeb Server is available at http://localhost:1313/ (bind address 127.0.0.1)\r\nPress Ctrl+C to stop\r\n\r\nCMD显示了这个,但是打开http://127.0.0.1:1313/ 显示的是Page Not Found\r\n\r\n我有重命名对应文件夹,但是全部放在E盘,然后下载的是hugo_0.120.4_windows-amd64 (没有)\r\n\r\n重新下载了[hugo_0.89.4_Windows-64bit.zip](https://github.com/gohugoio/hugo/releases/download/v0.89.4/hugo_0.89.4_Windows-64bit.zip) \r\n\r\n名字一模一样 问题 解决', 'author': {'login': 'CharlieLZ'}}, {'body': '非常好,感谢感谢 ', 'author': {'login': 'takayashoshi888'}}, {'body': '用hugo server启动的时候 一切都是正常的,但是hugo -D 生成静态之后左侧、顶部导航栏图标不能显示了,变成了一个方块。大佬这个怎么解决,感谢。', 'author': {'login': 'konglquan'}}, {'body': '希望安装步骤写完整一点,linux 的安装方法写详细一点。生成的网站样式错误,图片文件和样式文件加载全是404。', 'author': {'login': 'jiespring'}}, {'body': '想修改一下网格背景,但是为什么修改了custom-style.css这个文件后,网站样式没有变化啊。', 'author': {'login': 'dsshbz'}}, {'body': '这文档可以写得再清晰一点,看着有点晕啊', 'author': {'login': 'musica2016'}}]}}, {'title': '在 Linux 上给用户赋予指定目录的读写权限', 'number': 9, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/9', 'createdAt': '2023-10-23T05:16:10Z', 'lastEditedAt': '2024-08-27T02:11:37Z', 'updatedAt': '2024-08-27T02:11:37Z', 'body': '在 Linux 上指定目录的读写权限赋予用户,有两种方法可以实现这个目标:第一种是使用 ACL (访问控制列表),第二种是创建用户组来管理文件权限,下面会一一介绍。为了完成这个教程,我们将使用以下设置:\r\n\r\n- 操作系统:CentOS 7\r\n- 测试目录:/data/share\r\n- 测试用户:shenweiyan\r\n- 文件系统类型:ext4\r\n\r\n请确认所有的命令都是使用 root 用户执行的,或者使用 sudo 命令来享受与之同样的权限。让我们开始吧!下面,先使用 mkdir 命令来创建一个名为 share 的目录。\r\n\r\n```bash\r\n$ mkdir -p /data/share\r\n```\r\n\r\n## 1. ACL 权限设置\r\n\r\n**重要提示:** \r\n打算使用此方法的话,您需要确认您的 Linux 文件系统类型(如 ext3 和 ext4, NTFS, BTRFS)支持 ACL。\r\n\r\n### 1.1. 查看内核是否支持 ACL\r\n\r\n依照以下命令在您的系统中检查当前文件系统类型,并且查看内核是否支持 ACL:**\r\n\r\n```bash\r\n$ df -T | awk \'{print $1,$2,$NF}\' | grep "^/dev"\r\n$ grep -i acl /boot/config*\r\n```\r\n\r\n从下方的截屏可以看到,文件系统类型是 ext4,并且从 `CONFIG_EXT4_FS_POSIX_ACL=y` 选项可以发现内核是支持 POSIX ACL 的。\r\n![config-ext4-fs-posix-acl](https://kg.weiyan.cc/2024/08/config-ext4-fs-posix-acl.webp)\r\n\r\n### 1.2. 挂载是否使用了 ACL\r\n\r\n使用下面的命令,查看文件系统(分区)挂载时是否使用了 ACL 选项。\r\n\r\n```bash\r\n$ tune2fs -l /dev/vda1 | grep acl\r\n```\r\n\r\n![tune2fs-acl](https://kg.weiyan.cc/2024/08/tune2fs-acl.webp) \r\n通过上边的输出可以发现,默认的挂载项目中已经对 ACL 进行了支持。如果发现结果不如所愿,你可以通过以下命令对指定分区(此例中使用 /dev/sda3)开启 ACL 的支持)。\r\n\r\n```bash\r\n$ mount -o remount,acl /\r\n$ tune2fs -o acl /dev/sda3\r\n```\r\n\r\n### 1.3. 设置 ACL 权限\r\n\r\n```bash\r\nsetfacl -m m:rx 文件名 # 给 mask 的权限为 r-x ,使用 "m:rx"格式 \r\n\r\nsetfacl -m u:用户名:权限 -R 目录名 # 递归 ACL 权限(针对目录现有的文件设置 ACL) \r\n```\r\n\r\n例如,指定目录 `share` 的读写权限分配给名为 `shenweiyan` 的用户了,依照以下命令执行即可。\r\n\r\n```bash\r\n# 检查目录默认的 ACL 设置(Check the default ACL settings for the directory)\r\n$ getfacl /data/share\r\n\r\n# 指定用户读写权限(Give rw access to user shenweiyan)\r\n# 对于目录必须增加 x (执行)权限, 否则无法进入目录\r\n$ setfacl -m user:shenweiyan:rwx /data/share\r\n\r\n# 再次检查目录 ACL 设置(Check new ACL settings for the directory)\r\n$ getfacl /data/share\r\n```\r\n\r\n![setfacl-m-user](https://kg.weiyan.cc/2024/08/setfacl-m-user.webp) \r\n在上方的截屏中,通过输出结果的第二行 getfacl 命令可以发现,用户 shenweiyan 已经成功的被赋予了 /data/share 目录的读写权限。\r\n\r\n如果想要获取 ACL 列表的更多信息。请参考:\r\n\r\n- [如何使用访问控制列表(ACL)为用户/组设置磁盘配额](http://www.tecmint.com/set-access-control-lists-acls-and-disk-quotas-for-users-groups/)\r\n- [如何使用访问控制列表(ACL)挂载网络共享](http://www.tecmint.com/rhcsa-exam-configure-acls-and-mount-nfs-samba-shares/)\r\n\r\n### 1.4. 删除 ACL 权限\r\n\r\n如果用户名(组名)已经删除,可以使用 UID(GID)进行删除。\r\n\r\n```bash\r\nsetfacl -x u:用户名 文件名 # 删除指定用户的 ACL 权限\r\nsetfacl -x g:组名 文件名 # 删除指定组的 ACL 权限 \r\nsetfacl -b 文件名 # 删除文件下所有的 ACL 权限 \r\n```\r\n\r\n## 2. 用户组权限设置\r\n\r\n### 2.1. 变更属组\r\n\r\n如果用户已经拥有了默认的用户组(通常组名与用户名相同),就可以简单的通过变更文件夹的所属用户组来完成。\r\n\r\n```python\r\n$ chgrp shenweiyan /data/share\r\n```\r\n\r\n另外,我们也可以通过以下方法为多个用户(需要赋予指定目录读写权限的)新建一个用户组。如此一来,也就创建了一个共享目录。\r\n\r\n```python\r\n$ groupadd dbshare\r\n```\r\n\r\n### 2.2. 把用户添加到属组 \r\n\r\n接下来将用户 `shenweiyan` 添加到 `dbshare` 组中:\r\n\r\n```python\r\n# add user to projects\r\n$ usermod -aG dbshare shenweiyan\r\n\r\n# check users groups\r\n$ groups tecmint\r\n```\r\n\r\n### 2.3. 变更属组\r\n\r\n将目录的所属用户组变更为 `dbshare`:\r\n\r\n```python\r\n$ chgrp projects /data/share\r\n```\r\n\r\n### 2.4. 设置组员权限\r\n\r\n现在,给组成员设置读写权限。\r\n\r\n```bash\r\n$ chmod -R 0760 /data/share\r\n\r\n# check new permissions\r\n$ ls -l /data/share\r\n```\r\n\r\nok,在 Linux 上给用户赋予指定目录的读写权限就介绍到这里 !\r\n\r\n## 3. 参考资料\r\n\r\n- 高延斌,《[Linux ACL 体验](https://www.ibm.com/developerworks/cn/linux/l-acl/index.html)》,IBM Developer\r\n- Mr-Ping,《在 Linux 上给用户赋予指定目录的读写权限》,Linux 中国\r\n', 'bodyText': '在 Linux 上指定目录的读写权限赋予用户,有两种方法可以实现这个目标:第一种是使用 ACL (访问控制列表),第二种是创建用户组来管理文件权限,下面会一一介绍。为了完成这个教程,我们将使用以下设置:\n\n操作系统:CentOS 7\n测试目录:/data/share\n测试用户:shenweiyan\n文件系统类型:ext4\n\n请确认所有的命令都是使用 root 用户执行的,或者使用 sudo 命令来享受与之同样的权限。让我们开始吧!下面,先使用 mkdir 命令来创建一个名为 share 的目录。\n$ mkdir -p /data/share\n1. ACL 权限设置\n重要提示:\n打算使用此方法的话,您需要确认您的 Linux 文件系统类型(如 ext3 和 ext4, NTFS, BTRFS)支持 ACL。\n1.1. 查看内核是否支持 ACL\n依照以下命令在您的系统中检查当前文件系统类型,并且查看内核是否支持 ACL:**\n$ df -T | awk \'{print $1,$2,$NF}\' | grep "^/dev"\n$ grep -i acl /boot/config*\n从下方的截屏可以看到,文件系统类型是 ext4,并且从 CONFIG_EXT4_FS_POSIX_ACL=y 选项可以发现内核是支持 POSIX ACL 的。\n\n1.2. 挂载是否使用了 ACL\n使用下面的命令,查看文件系统(分区)挂载时是否使用了 ACL 选项。\n$ tune2fs -l /dev/vda1 | grep acl\n\n通过上边的输出可以发现,默认的挂载项目中已经对 ACL 进行了支持。如果发现结果不如所愿,你可以通过以下命令对指定分区(此例中使用 /dev/sda3)开启 ACL 的支持)。\n$ mount -o remount,acl /\n$ tune2fs -o acl /dev/sda3\n1.3. 设置 ACL 权限\nsetfacl -m m:rx 文件名 # 给 mask 的权限为 r-x ,使用 "m:rx"格式 \n\nsetfacl -m u:用户名:权限 -R 目录名 # 递归 ACL 权限(针对目录现有的文件设置 ACL) \n例如,指定目录 share 的读写权限分配给名为 shenweiyan 的用户了,依照以下命令执行即可。\n# 检查目录默认的 ACL 设置(Check the default ACL settings for the directory)\n$ getfacl /data/share\n\n# 指定用户读写权限(Give rw access to user shenweiyan)\n# 对于目录必须增加 x (执行)权限, 否则无法进入目录\n$ setfacl -m user:shenweiyan:rwx /data/share\n\n# 再次检查目录 ACL 设置(Check new ACL settings for the directory)\n$ getfacl /data/share\n\n在上方的截屏中,通过输出结果的第二行 getfacl 命令可以发现,用户 shenweiyan 已经成功的被赋予了 /data/share 目录的读写权限。\n如果想要获取 ACL 列表的更多信息。请参考:\n\n如何使用访问控制列表(ACL)为用户/组设置磁盘配额\n如何使用访问控制列表(ACL)挂载网络共享\n\n1.4. 删除 ACL 权限\n如果用户名(组名)已经删除,可以使用 UID(GID)进行删除。\nsetfacl -x u:用户名 文件名 # 删除指定用户的 ACL 权限\nsetfacl -x g:组名 文件名 # 删除指定组的 ACL 权限 \nsetfacl -b 文件名 # 删除文件下所有的 ACL 权限 \n2. 用户组权限设置\n2.1. 变更属组\n如果用户已经拥有了默认的用户组(通常组名与用户名相同),就可以简单的通过变更文件夹的所属用户组来完成。\n$ chgrp shenweiyan /data/share\n另外,我们也可以通过以下方法为多个用户(需要赋予指定目录读写权限的)新建一个用户组。如此一来,也就创建了一个共享目录。\n$ groupadd dbshare\n2.2. 把用户添加到属组\n接下来将用户 shenweiyan 添加到 dbshare 组中:\n# add user to projects\n$ usermod -aG dbshare shenweiyan\n\n# check users groups\n$ groups tecmint\n2.3. 变更属组\n将目录的所属用户组变更为 dbshare:\n$ chgrp projects /data/share\n2.4. 设置组员权限\n现在,给组成员设置读写权限。\n$ chmod -R 0760 /data/share\n\n# check new permissions\n$ ls -l /data/share\nok,在 Linux 上给用户赋予指定目录的读写权限就介绍到这里 !\n3. 参考资料\n\n高延斌,《Linux ACL 体验》,IBM Developer\nMr-Ping,《在 Linux 上给用户赋予指定目录的读写权限》,Linux 中国', 'bodyHTML': '

在 Linux 上指定目录的读写权限赋予用户,有两种方法可以实现这个目标:第一种是使用 ACL (访问控制列表),第二种是创建用户组来管理文件权限,下面会一一介绍。为了完成这个教程,我们将使用以下设置:

\n
    \n
  • 操作系统:CentOS 7
  • \n
  • 测试目录:/data/share
  • \n
  • 测试用户:shenweiyan
  • \n
  • 文件系统类型:ext4
  • \n
\n

请确认所有的命令都是使用 root 用户执行的,或者使用 sudo 命令来享受与之同样的权限。让我们开始吧!下面,先使用 mkdir 命令来创建一个名为 share 的目录。

\n
$ mkdir -p /data/share
\n

1. ACL 权限设置

\n

重要提示:
\n打算使用此方法的话,您需要确认您的 Linux 文件系统类型(如 ext3 和 ext4, NTFS, BTRFS)支持 ACL。

\n

1.1. 查看内核是否支持 ACL

\n

依照以下命令在您的系统中检查当前文件系统类型,并且查看内核是否支持 ACL:**

\n
$ df -T | awk \'{print $1,$2,$NF}\' | grep "^/dev"\n$ grep -i acl /boot/config*
\n

从下方的截屏可以看到,文件系统类型是 ext4,并且从 CONFIG_EXT4_FS_POSIX_ACL=y 选项可以发现内核是支持 POSIX ACL 的。
\nconfig-ext4-fs-posix-acl

\n

1.2. 挂载是否使用了 ACL

\n

使用下面的命令,查看文件系统(分区)挂载时是否使用了 ACL 选项。

\n
$ tune2fs -l /dev/vda1 | grep acl
\n

tune2fs-acl
\n通过上边的输出可以发现,默认的挂载项目中已经对 ACL 进行了支持。如果发现结果不如所愿,你可以通过以下命令对指定分区(此例中使用 /dev/sda3)开启 ACL 的支持)。

\n
$ mount -o remount,acl /\n$ tune2fs -o acl /dev/sda3
\n

1.3. 设置 ACL 权限

\n
setfacl -m m:rx 文件名    # 给 mask 的权限为 r-x ,使用 "m:rx"格式 \n\nsetfacl -m u:用户名:权限 -R 目录名   # 递归 ACL 权限(针对目录现有的文件设置 ACL) 
\n

例如,指定目录 share 的读写权限分配给名为 shenweiyan 的用户了,依照以下命令执行即可。

\n
# 检查目录默认的 ACL 设置(Check the default ACL settings for the directory)\n$ getfacl /data/share\n\n# 指定用户读写权限(Give rw access to user shenweiyan)\n# 对于目录必须增加 x (执行)权限, 否则无法进入目录\n$ setfacl -m user:shenweiyan:rwx /data/share\n\n# 再次检查目录 ACL 设置(Check new ACL settings for the directory)\n$ getfacl /data/share
\n

setfacl-m-user
\n在上方的截屏中,通过输出结果的第二行 getfacl 命令可以发现,用户 shenweiyan 已经成功的被赋予了 /data/share 目录的读写权限。

\n

如果想要获取 ACL 列表的更多信息。请参考:

\n\n

1.4. 删除 ACL 权限

\n

如果用户名(组名)已经删除,可以使用 UID(GID)进行删除。

\n
setfacl -x u:用户名 文件名     # 删除指定用户的 ACL 权限\nsetfacl -x g:组名   文件名     # 删除指定组的 ACL 权限 \nsetfacl -b 文件名              # 删除文件下所有的 ACL 权限 
\n

2. 用户组权限设置

\n

2.1. 变更属组

\n

如果用户已经拥有了默认的用户组(通常组名与用户名相同),就可以简单的通过变更文件夹的所属用户组来完成。

\n
$ chgrp shenweiyan /data/share
\n

另外,我们也可以通过以下方法为多个用户(需要赋予指定目录读写权限的)新建一个用户组。如此一来,也就创建了一个共享目录。

\n
$ groupadd dbshare
\n

2.2. 把用户添加到属组

\n

接下来将用户 shenweiyan 添加到 dbshare 组中:

\n
# add user to projects\n$ usermod -aG dbshare shenweiyan\n\n# check users groups\n$ groups tecmint
\n

2.3. 变更属组

\n

将目录的所属用户组变更为 dbshare

\n
$ chgrp projects /data/share
\n

2.4. 设置组员权限

\n

现在,给组成员设置读写权限。

\n
$ chmod -R 0760 /data/share\n\n# check new permissions\n$ ls -l /data/share
\n

ok,在 Linux 上给用户赋予指定目录的读写权限就介绍到这里 !

\n

3. 参考资料

\n
    \n
  • 高延斌,《Linux ACL 体验》,IBM Developer
  • \n
  • Mr-Ping,《在 Linux 上给用户赋予指定目录的读写权限》,Linux 中国
  • \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '1.3.17-服务器配置使用'}]}, 'comments': {'nodes': []}}, {'title': '个人域名跳转至语雀个人主页', 'number': 8, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/8', 'createdAt': '2023-10-23T01:51:34Z', 'lastEditedAt': '2023-10-23T01:54:54Z', 'updatedAt': '2024-01-03T07:58:05Z', 'body': '> 📢 域名 [https://weiyan.cc](https://weiyan.cc) 就是基于本文章中的 "**[无服务器](#pG3U6)**" 步骤实现的个人域名跳转至语雀个人主页!因此,本篇文档你也可以通过以下的链接访问:[https://weiyan.cc/cookbook/301-redirects](https://weiyan.cc/cookbook/301-redirects)!\r\n\r\n语雀的个人使用目前是不支持自定义域名的,虽然空间的使用可以自定义二级域名,如:[weiyan.yuque.com](https://weiyan.yuque.com/),但是空间知识库必须要先登录,不方便其他人查看,尤其是对于没有注册语雀的用户。\r\n\r\n现在的情况是,我有一个已经备案的个人域名 `www.example.com`,现在我想:\r\n\r\n- 让所有 `www.example.com` 的访问地址都跳转到 ,比如 `https://www.example.com/cookbook` 跳转到 。\r\n- `www.example.com` 的访问地址跳转同时支持 http/https。\r\n- `example.com/www.example.com` 同时实现以上跳转。\r\n\r\n反正就一句话,让下面的链接都跳转到 :\r\n\r\n- \r\n- \r\n- \r\n- \r\n\r\n下面简单记录一下具体的实现过程。\r\n\r\n## 背景知识\r\n\r\n**显性 URL 转发:** 用的是 301 重定向技术,效果为浏览器地址栏输入 [http://a.com](http://a.com/) 回车,打开网站内容是目标地址 的网站内容,且地址栏显示目标地址 [http://cloud.baidu.com/](http://cloud.baidu.com/) 。\r\n\r\n**隐性 URL 转发:** 用的是 iframe 框架技术、非重定向技术,效果为浏览器地址栏输入 [http://a.com](http://a.com/) 回车,打开网站内容是目标地址 的网站内容,但地址栏显示当前地址 [http://a.com](http://a.com/) 。\r\n\r\n**301 重定向是什么?**\r\n\r\n301 重定向表示网页由一个地址永久地移动到了另外一个地址。这里中的 301 是被重定向网页的 HTTP 状态代码。\r\n\r\n**例如:** [blog.ahrefs.com](https://blog.ahrefs.com/) 重定向到了 [ahrefs.com/blog](https://ahrefs.com/blog)。\r\n\r\n简单来说,301 重定向是在告诉浏览器:“这个页面已经永久迁移了。这个是新的地址,我们不打算把它移回去啦。”这时,浏览器会回复:“没问题!我现在(开始)就把用户引向这里!”\r\n\r\n这就是为什么访问 blog.ahrefs.com 已经不可能了。你最后会去到的网页是 ahrefs.com/blog。\r\n\r\n## 前提条件\r\n\r\n前提条件可以分为**有服务器**和**无服务器**两种情况,下面具体说一下。\r\n\r\n1. 有服务器(可以考虑腾讯云或者阿里云的轻量云服务器,双十一优惠价一年也就几十块);\r\n\r\n - 阿里云轻量云服务器:[购买链接](https://www.aliyun.com/activity/1111?userCode=mx65q35j)\r\n - 腾讯云轻量云服务器:[购买链接](https://curl.qcloud.com/0Sy0R0AX)\r\n - 域名(域名需要已经完成备案);\r\n - SSL 证书(可以使用阿里云或者腾讯云的免费域名证书);\r\n\r\n2. 无服务器\r\n - 可以考虑使用 [Cloudflare Page Rules](https://support.cloudflare.com/hc/zh-cn/articles/218411427)(页面规则);当然,其他的平台也可以;\r\n - 域名(有些域名可以不用备案);\r\n - SSL 证书(如果你用的是 [Cloudflare Page Rules](https://support.cloudflare.com/hc/zh-cn/articles/218411427),可以不用 SSL 证书 )。\r\n\r\n## 操作步骤:有服务器\r\n\r\n本操作以 **ncbix.com** 域名为示例。\r\n\r\n### 1. 域名解析\r\n\r\n在你的域名供应商后台点击“添加记录”,分别输入 www 和 @,记录类型“A”,记录值就是你虚拟主机或 VPS 服务器的 IP 地址,最后保存。以 DNSPOD 为例。\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FqvWUx6cyUz-O8d1avOdFZ1aDIWF.png)\r\n\r\n### 2. SSL 证书\r\n\r\n申请免费证书,具体操作可以自行百度。以腾讯云为例:。\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/Fo4XBIRStXxx27kvjKULIjHazdJ9.png)\r\n根据截图,一步步点击操作。申请完成后,把证书下载并上传到你的服务器。\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FqamrO4EBSQuO6wsJ28y8g-AH63E.png)\r\n\r\n### 3. 安装 Nginx\r\n\r\n可以直接使用 **yum/apt** 的方式直接安装;源码方式的安装,参考:《[CentOS 7 下编译安装 Nginx · 语雀](https://www.yuque.com/shenweiyan/cookbook/centos-install-nginx)》。\r\n\r\n```bash\r\n# Debian/Ubuntu\r\napt update\r\napt install nginx\r\n\r\n# CentOS/RHEL\r\nyum install nginx\r\n```\r\n\r\n### 4. 配置 Nginx\r\n\r\n通过 **yum/apt** 安装的 Nginx 默认的置文件在 **/etc/nginx/nginx.conf**,编辑该文件。\r\n\r\n```nginx\r\nhttp {\r\n ##\r\n # Basic Settings\r\n ##\r\n ......\r\n\r\n ##\r\n # Virtual Host Configs\r\n ##\r\nserver {\r\n listen 80;\r\n listen 443 ssl;\r\n server_name ncbix.com www.ncbix.com;\r\n ssl_certificate /etc/nginx/ssl/nginx/www.ncbix.com_bundle.crt;\r\n ssl_certificate_key /etc/nginx/ssl/nginx/www.ncbix.com.key;\r\n index index.php index.html index.htm;\r\n\r\n if ( $scheme = "http" ) {\r\n return 301 https://www.yuque.com/shenweiyan$request_uri; #确保跳转到新域名HTTPS如果没有HTTPS可以去掉\r\n }\r\n location / {\r\n rewrite /.* https://www.yuque.com/shenweiyan$uri redirect; #跳转到新域名并重写为新域名\r\n }\r\n }\r\n\r\ninclude /etc/nginx/conf.d/*.conf;\r\n include /etc/nginx/sites-enabled/*;\r\n}\r\n```\r\n\r\n### 5. 重启 Nginx\r\n\r\n最后,通过下面的命令重启 Nginx 服务即可。\r\n\r\n```bash\r\nservice nginx restart\r\n```\r\n\r\n## 操作步骤:无服务器\r\n\r\n我们以 [Cloudflare Page Rules](https://support.cloudflare.com/hc/zh-cn/articles/218411427) 为例,说明一下具体怎么操作。\r\n\r\n### 1. Cloudflare 中添加站点\r\n\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/Fjd2wS9yVs0ZiBBalZQVOuPQHbU1.png)\r\n\r\n添加完站点后,可以选择 **Free 计划**,然后点击继续:\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FumaUELUaIJnv9s0Q4paKUDIAWTL.png)\r\n\r\n点击继续后,Cloudflare 会自动扫描你对应域名的一些解析记录:\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FtQZKAyQd_6dd5d7A_ZLCVp4NUEg.png)\r\n\r\n我们可以直接选择 **"继续"**。\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/Fvkt0gHVP7lmiqapWf3pM7Zx4YwN.png)\r\n\r\n### 2. 修改域名 DNS\r\n\r\n首先,我的域名是在腾讯云注册的,可以去腾讯云控制台 **"我的域名"** 中直接修改 DNS:\r\n\r\n```\r\n# 添加 Cloudflare 名称服务器\r\nimani.ns.cloudflare.com\r\ncaroline.dnspod.net\r\n```\r\n\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FlKyYHHLGHwD9IPKYvLtPorghBpr.png)\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FmRwodrlbkBt6SkX7RsG2ec1iruc.png)\r\n\r\n### 3. 完成 Cloudflare 添加站点\r\n\r\n可以把后面快速指南的这几个配置都勾选。\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FtULJ4uM_TuPjPkkMtdXAhxpyDes.png)\r\n\r\n等待几分钟就可以看到你的域名站点已经添加到 Cloudflare 上了!\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/Fk8Hv5dkW8kHd1IorhNfT427RliQ.png)\r\n\r\n### 4. 设置 DNS 记录\r\n\r\n> The first thing you will need is a DNS record for **@**, **www** and any other subdomains you want to redirect, set to ![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FjjhP041Zj-aZVPAHpQ-YnHIzMA6.png). This can point to any IP address as the redirection page rule will execute first. I would recommend pointing them to 192.0.2.1 , a dummy IP.\r\n>\r\n> From:\r\n\r\n在配置 Cloudflare 站点的页面规则前,你需要把该域名的 **@**,**www** 或者其他你想要进行重定向的子域名添加到 DNS 记录中,这个记录的值可以指向任何 IP 地址,因为重定向页面规则将首先执行。我建议将它们指向 192.0.2.1 ,一个虚拟 IP。\r\n\r\n在这里,我们以 **@** 和 **note** 子域名为例,添加 DNS 记录,先让它们指向一个虚拟 IP。\r\n![images](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/Fk08ydFuPukTv88AAa0V27T4xTBh.png "以 ncbix.com 和 note.ncbix.com 为例,均重定向到 https://www.yuque.com/shenweiyan 页面")\r\n\r\n### 5. 配置 Cloudflare 站点页面规则\r\n\r\n首先,在 Cloudflare 的主页上点击对应的站点,选择 **"页面规则"**,点击。\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FqolXaSzUdkgtKo66yRC3xRkV7mv.png)\r\n\r\n点击 **"创建页面规则"**:\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FnF2bk6hzYvulCtXdLSQSUiV1Z44.png)\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/Fp5DSLxKInn25a591hjYjDNpUeRn.png)\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FiFuRSizKlmkmJ5LxiBfkIGreBdm.png)\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FtNPR2rLIFDKMYz3N8gqkLBcQFnG.png)\r\n\r\n#### 什么是页面规则?\r\n\r\n> 页面规则为 Cloudflare 设置提供基于 URL 的粒度控制。关于页面规则需要了解的最重要事情是,针对一个 URL 仅触发一个页面规则,因此一定要按照优先级顺序对页面规则进行排序并将最具体的页面规则放在顶部。\r\n\r\n##### 页面规则中允许哪些模式?\r\n\r\n> 如果使用的是转发页面规则,则可以将这些通配符映射到变量。在转发 URL 中,可以按照从左到右的顺序指定与原始 URL 中的通配符相匹配的 $1、$2,以此类推。\r\n>\r\n> 例如,可以将 `http://.example.com/` 转发到 `http://$2.example.com/$1.jpg`。此规则将与 相匹配,这最终将转发到 。\r\n\r\n##### 一些有用的提示:\r\n\r\n> 1. 如果要同时匹配 http 和 https,只需编写 example.com 即可。无需编写 example.com。\r\n> 2. 如果要匹配域中的每个页面,则需要编写 example.com/,仅编写 example.com 是不够的。\r\n> 3. 请参阅 [了解和配置 Cloudflare 页面规则](https://support.cloudflare.com/hc/articles/218411427) 了解有关页面规则模式的更多详细信息。\r\n\r\n### 6. 配置 SSL(不必要)\r\n\r\n**📢 Update 2022.09.05:这一步不是必要的,这里仅供参考!**\r\n\r\n1. 申请 [www.example.com](http://www.example.com) 域名的 SSL 证书;\r\n2. 把 DNS 验证域名的记录添加到 Cloudfare 的 DNS 中;\r\n\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FiEmXujpQKK0j0p2GxzaOgTC3xwN.png)\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FnOHAmNIAcEmwBD_fv3eIUBzxmiB.png)\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FtxcA4iXJhT029vkw35EVkDN-2QG.png)\r\n\r\n**注意:**\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FgrIb03h7Inot6k7fa1BHGH4G3HO.png)\r\n\r\n## 参考资料\r\n\r\n1. [nginx 实现两个域名之间跳转配置 - SegmentFault 思否](https://segmentfault.com/q/1010000015157572)\r\n2. [智能云解析 DNS - 通过 Nginx 实现 URL 转发 | 百度智能云文档](https://cloud.baidu.com/doc/DNS/s/ukq4w1pji)\r\n3. [SEO 的 301 重定向:你需要知道的一切](https://ahrefs.com/blog/zh/301-redirects/)\r\n', 'bodyText': '📢 域名 https://weiyan.cc 就是基于本文章中的 "无服务器" 步骤实现的个人域名跳转至语雀个人主页!因此,本篇文档你也可以通过以下的链接访问:https://weiyan.cc/cookbook/301-redirects!\n\n语雀的个人使用目前是不支持自定义域名的,虽然空间的使用可以自定义二级域名,如:weiyan.yuque.com,但是空间知识库必须要先登录,不方便其他人查看,尤其是对于没有注册语雀的用户。\n现在的情况是,我有一个已经备案的个人域名 www.example.com,现在我想:\n\n让所有 www.example.com 的访问地址都跳转到 https://www.yuque.com/shenweiyan,比如 https://www.example.com/cookbook 跳转到 https://www.yuque.com/shenweiyan/cookbook。\nwww.example.com 的访问地址跳转同时支持 http/https。\nexample.com/www.example.com 同时实现以上跳转。\n\n反正就一句话,让下面的链接都跳转到 https://www.yuque.com/shenweiyan:\n\nhttp://example.com\nhttp://www.example.com\nhttps://example.com\nhttps://www.example.com\n\n下面简单记录一下具体的实现过程。\n背景知识\n显性 URL 转发: 用的是 301 重定向技术,效果为浏览器地址栏输入 http://a.com 回车,打开网站内容是目标地址 http://cloud.baidu.com/ 的网站内容,且地址栏显示目标地址 http://cloud.baidu.com/ 。\n隐性 URL 转发: 用的是 iframe 框架技术、非重定向技术,效果为浏览器地址栏输入 http://a.com 回车,打开网站内容是目标地址 http://cloud.baidu.com/ 的网站内容,但地址栏显示当前地址 http://a.com 。\n301 重定向是什么?\n301 重定向表示网页由一个地址永久地移动到了另外一个地址。这里中的 301 是被重定向网页的 HTTP 状态代码。\n例如: blog.ahrefs.com 重定向到了 ahrefs.com/blog。\n简单来说,301 重定向是在告诉浏览器:“这个页面已经永久迁移了。这个是新的地址,我们不打算把它移回去啦。”这时,浏览器会回复:“没问题!我现在(开始)就把用户引向这里!”\n这就是为什么访问 blog.ahrefs.com 已经不可能了。你最后会去到的网页是 ahrefs.com/blog。\n前提条件\n前提条件可以分为有服务器和无服务器两种情况,下面具体说一下。\n\n\n有服务器(可以考虑腾讯云或者阿里云的轻量云服务器,双十一优惠价一年也就几十块);\n\n阿里云轻量云服务器:购买链接\n腾讯云轻量云服务器:购买链接\n域名(域名需要已经完成备案);\nSSL 证书(可以使用阿里云或者腾讯云的免费域名证书);\n\n\n\n无服务器\n\n可以考虑使用 Cloudflare Page Rules(页面规则);当然,其他的平台也可以;\n域名(有些域名可以不用备案);\nSSL 证书(如果你用的是 Cloudflare Page Rules,可以不用 SSL 证书 )。\n\n\n\n操作步骤:有服务器\n本操作以 ncbix.com 域名为示例。\n1. 域名解析\n在你的域名供应商后台点击“添加记录”,分别输入 www 和 @,记录类型“A”,记录值就是你虚拟主机或 VPS 服务器的 IP 地址,最后保存。以 DNSPOD 为例。\n\n2. SSL 证书\n申请免费证书,具体操作可以自行百度。以腾讯云为例:https://console.cloud.tencent.com/ssl。\n\n根据截图,一步步点击操作。申请完成后,把证书下载并上传到你的服务器。\n\n3. 安装 Nginx\n可以直接使用 yum/apt 的方式直接安装;源码方式的安装,参考:《CentOS 7 下编译安装 Nginx · 语雀》。\n# Debian/Ubuntu\napt update\napt install nginx\n\n# CentOS/RHEL\nyum install nginx\n4. 配置 Nginx\n通过 yum/apt 安装的 Nginx 默认的置文件在 /etc/nginx/nginx.conf,编辑该文件。\nhttp {\n ##\n # Basic Settings\n ##\n ......\n\n ##\n # Virtual Host Configs\n ##\nserver {\n listen 80;\n listen 443 ssl;\n server_name ncbix.com www.ncbix.com;\n ssl_certificate /etc/nginx/ssl/nginx/www.ncbix.com_bundle.crt;\n ssl_certificate_key /etc/nginx/ssl/nginx/www.ncbix.com.key;\n index index.php index.html index.htm;\n\n if ( $scheme = "http" ) {\n return 301 https://www.yuque.com/shenweiyan$request_uri; #确保跳转到新域名HTTPS如果没有HTTPS可以去掉\n }\n location / {\n rewrite /.* https://www.yuque.com/shenweiyan$uri redirect; #跳转到新域名并重写为新域名\n }\n }\n\ninclude /etc/nginx/conf.d/*.conf;\n include /etc/nginx/sites-enabled/*;\n}\n5. 重启 Nginx\n最后,通过下面的命令重启 Nginx 服务即可。\nservice nginx restart\n操作步骤:无服务器\n我们以 Cloudflare Page Rules 为例,说明一下具体怎么操作。\n1. Cloudflare 中添加站点\n\n添加完站点后,可以选择 Free 计划,然后点击继续:\n\n点击继续后,Cloudflare 会自动扫描你对应域名的一些解析记录:\n\n我们可以直接选择 "继续"。\n\n2. 修改域名 DNS\n首先,我的域名是在腾讯云注册的,可以去腾讯云控制台 "我的域名" 中直接修改 DNS:\n# 添加 Cloudflare 名称服务器\nimani.ns.cloudflare.com\ncaroline.dnspod.net\n\n\n\n3. 完成 Cloudflare 添加站点\n可以把后面快速指南的这几个配置都勾选。\n\n等待几分钟就可以看到你的域名站点已经添加到 Cloudflare 上了!\n\n4. 设置 DNS 记录\n\nThe first thing you will need is a DNS record for @, www and any other subdomains you want to redirect, set to . This can point to any IP address as the redirection page rule will execute first. I would recommend pointing them to 192.0.2.1 , a dummy IP.\nFrom:https://community.cloudflare.com/t/redirecting-one-domain-to-another/81960\n\n在配置 Cloudflare 站点的页面规则前,你需要把该域名的 @,www 或者其他你想要进行重定向的子域名添加到 DNS 记录中,这个记录的值可以指向任何 IP 地址,因为重定向页面规则将首先执行。我建议将它们指向 192.0.2.1 ,一个虚拟 IP。\n在这里,我们以 @ 和 note 子域名为例,添加 DNS 记录,先让它们指向一个虚拟 IP。\n\n5. 配置 Cloudflare 站点页面规则\n首先,在 Cloudflare 的主页上点击对应的站点,选择 "页面规则",点击。\n\n点击 "创建页面规则":\n\n\n\n\n什么是页面规则?\n\n页面规则为 Cloudflare 设置提供基于 URL 的粒度控制。关于页面规则需要了解的最重要事情是,针对一个 URL 仅触发一个页面规则,因此一定要按照优先级顺序对页面规则进行排序并将最具体的页面规则放在顶部。\n\n页面规则中允许哪些模式?\n\n如果使用的是转发页面规则,则可以将这些通配符映射到变量。在转发 URL 中,可以按照从左到右的顺序指定与原始 URL 中的通配符相匹配的 $1、$2,以此类推。\n例如,可以将 http://.example.com/ 转发到 http://$2.example.com/$1.jpg。此规则将与 http://cloud.example.com/flare 相匹配,这最终将转发到 http://flare.example.com/cloud.jpg。\n\n一些有用的提示:\n\n\n如果要同时匹配 http 和 https,只需编写 example.com 即可。无需编写 example.com。\n如果要匹配域中的每个页面,则需要编写 example.com/,仅编写 example.com 是不够的。\n请参阅 了解和配置 Cloudflare 页面规则 了解有关页面规则模式的更多详细信息。\n\n\n6. 配置 SSL(不必要)\n📢 Update 2022.09.05:这一步不是必要的,这里仅供参考!\n\n申请 www.example.com 域名的 SSL 证书;\n把 DNS 验证域名的记录添加到 Cloudfare 的 DNS 中;\n\n\n\n\n注意:\n\n参考资料\n\nnginx 实现两个域名之间跳转配置 - SegmentFault 思否\n智能云解析 DNS - 通过 Nginx 实现 URL 转发 | 百度智能云文档\nSEO 的 301 重定向:你需要知道的一切', 'bodyHTML': '
\n

📢 域名 https://weiyan.cc 就是基于本文章中的 "无服务器" 步骤实现的个人域名跳转至语雀个人主页!因此,本篇文档你也可以通过以下的链接访问:https://weiyan.cc/cookbook/301-redirects

\n
\n

语雀的个人使用目前是不支持自定义域名的,虽然空间的使用可以自定义二级域名,如:weiyan.yuque.com,但是空间知识库必须要先登录,不方便其他人查看,尤其是对于没有注册语雀的用户。

\n

现在的情况是,我有一个已经备案的个人域名 www.example.com,现在我想:

\n\n

反正就一句话,让下面的链接都跳转到 https://www.yuque.com/shenweiyan

\n\n

下面简单记录一下具体的实现过程。

\n

背景知识

\n

显性 URL 转发: 用的是 301 重定向技术,效果为浏览器地址栏输入 http://a.com 回车,打开网站内容是目标地址 http://cloud.baidu.com/ 的网站内容,且地址栏显示目标地址 http://cloud.baidu.com/

\n

隐性 URL 转发: 用的是 iframe 框架技术、非重定向技术,效果为浏览器地址栏输入 http://a.com 回车,打开网站内容是目标地址 http://cloud.baidu.com/ 的网站内容,但地址栏显示当前地址 http://a.com

\n

301 重定向是什么?

\n

301 重定向表示网页由一个地址永久地移动到了另外一个地址。这里中的 301 是被重定向网页的 HTTP 状态代码。

\n

例如: blog.ahrefs.com 重定向到了 ahrefs.com/blog

\n

简单来说,301 重定向是在告诉浏览器:“这个页面已经永久迁移了。这个是新的地址,我们不打算把它移回去啦。”这时,浏览器会回复:“没问题!我现在(开始)就把用户引向这里!”

\n

这就是为什么访问 blog.ahrefs.com 已经不可能了。你最后会去到的网页是 ahrefs.com/blog。

\n

前提条件

\n

前提条件可以分为有服务器无服务器两种情况,下面具体说一下。

\n
    \n
  1. \n

    有服务器(可以考虑腾讯云或者阿里云的轻量云服务器,双十一优惠价一年也就几十块);

    \n
      \n
    • 阿里云轻量云服务器:购买链接
    • \n
    • 腾讯云轻量云服务器:购买链接
    • \n
    • 域名(域名需要已经完成备案);
    • \n
    • SSL 证书(可以使用阿里云或者腾讯云的免费域名证书);
    • \n
    \n
  2. \n
  3. \n

    无服务器

    \n
      \n
    • 可以考虑使用 Cloudflare Page Rules(页面规则);当然,其他的平台也可以;
    • \n
    • 域名(有些域名可以不用备案);
    • \n
    • SSL 证书(如果你用的是 Cloudflare Page Rules,可以不用 SSL 证书 )。
    • \n
    \n
  4. \n
\n

操作步骤:有服务器

\n

本操作以 ncbix.com 域名为示例。

\n

1. 域名解析

\n

在你的域名供应商后台点击“添加记录”,分别输入 www 和 @,记录类型“A”,记录值就是你虚拟主机或 VPS 服务器的 IP 地址,最后保存。以 DNSPOD 为例。
\nimage.png

\n

2. SSL 证书

\n

申请免费证书,具体操作可以自行百度。以腾讯云为例:https://console.cloud.tencent.com/ssl
\nimage.png
\n根据截图,一步步点击操作。申请完成后,把证书下载并上传到你的服务器。
\nimage.png

\n

3. 安装 Nginx

\n

可以直接使用 yum/apt 的方式直接安装;源码方式的安装,参考:《CentOS 7 下编译安装 Nginx · 语雀》。

\n
# Debian/Ubuntu\napt update\napt install nginx\n\n# CentOS/RHEL\nyum install nginx
\n

4. 配置 Nginx

\n

通过 yum/apt 安装的 Nginx 默认的置文件在 /etc/nginx/nginx.conf,编辑该文件。

\n
http {\n    ##\n    # Basic Settings\n    ##\n    ......\n\n    ##\n    # Virtual Host Configs\n    ##\nserver {\n    listen 80;\n    listen 443 ssl;\n    server_name ncbix.com www.ncbix.com;\n    ssl_certificate /etc/nginx/ssl/nginx/www.ncbix.com_bundle.crt;\n    ssl_certificate_key /etc/nginx/ssl/nginx/www.ncbix.com.key;\n    index  index.php index.html index.htm;\n\n    if ( $scheme = "http" ) {\n        return 301 https://www.yuque.com/shenweiyan$request_uri; #确保跳转到新域名HTTPS如果没有HTTPS可以去掉\n    }\n    location / {\n        rewrite /.* https://www.yuque.com/shenweiyan$uri redirect; #跳转到新域名并重写为新域名\n    }\n  }\n\ninclude /etc/nginx/conf.d/*.conf;\n    include /etc/nginx/sites-enabled/*;\n}
\n

5. 重启 Nginx

\n

最后,通过下面的命令重启 Nginx 服务即可。

\n
service nginx restart
\n

操作步骤:无服务器

\n

我们以 Cloudflare Page Rules 为例,说明一下具体怎么操作。

\n

1. Cloudflare 中添加站点

\n

image.png

\n

添加完站点后,可以选择 Free 计划,然后点击继续:
\nimage.png

\n

点击继续后,Cloudflare 会自动扫描你对应域名的一些解析记录:
\nimage.png

\n

我们可以直接选择 "继续"
\nimage.png

\n

2. 修改域名 DNS

\n

首先,我的域名是在腾讯云注册的,可以去腾讯云控制台 "我的域名" 中直接修改 DNS:

\n
# 添加 Cloudflare 名称服务器\nimani.ns.cloudflare.com\ncaroline.dnspod.net\n
\n

image.png
\nimage.png

\n

3. 完成 Cloudflare 添加站点

\n

可以把后面快速指南的这几个配置都勾选。
\nimage.png

\n

等待几分钟就可以看到你的域名站点已经添加到 Cloudflare 上了!
\nimage.png

\n

4. 设置 DNS 记录

\n
\n

The first thing you will need is a DNS record for @, www and any other subdomains you want to redirect, set to image.png. This can point to any IP address as the redirection page rule will execute first. I would recommend pointing them to 192.0.2.1 , a dummy IP.

\n

From:https://community.cloudflare.com/t/redirecting-one-domain-to-another/81960

\n
\n

在配置 Cloudflare 站点的页面规则前,你需要把该域名的 @www 或者其他你想要进行重定向的子域名添加到 DNS 记录中,这个记录的值可以指向任何 IP 地址,因为重定向页面规则将首先执行。我建议将它们指向 192.0.2.1 ,一个虚拟 IP。

\n

在这里,我们以 @note 子域名为例,添加 DNS 记录,先让它们指向一个虚拟 IP。
\nimages

\n

5. 配置 Cloudflare 站点页面规则

\n

首先,在 Cloudflare 的主页上点击对应的站点,选择 "页面规则",点击。
\nimage.png

\n

点击 "创建页面规则"
\nimage.png
\nimage.png
\nimage.png
\nimage.png

\n

什么是页面规则?

\n
\n

页面规则为 Cloudflare 设置提供基于 URL 的粒度控制。关于页面规则需要了解的最重要事情是,针对一个 URL 仅触发一个页面规则,因此一定要按照优先级顺序对页面规则进行排序并将最具体的页面规则放在顶部。

\n
\n
页面规则中允许哪些模式?
\n
\n

如果使用的是转发页面规则,则可以将这些通配符映射到变量。在转发 URL 中,可以按照从左到右的顺序指定与原始 URL 中的通配符相匹配的 $1、$2,以此类推。

\n

例如,可以将 http://.example.com/ 转发到 http://$2.example.com/$1.jpg。此规则将与 http://cloud.example.com/flare 相匹配,这最终将转发到 http://flare.example.com/cloud.jpg

\n
\n
一些有用的提示:
\n
\n
    \n
  1. 如果要同时匹配 http 和 https,只需编写 example.com 即可。无需编写 example.com。
  2. \n
  3. 如果要匹配域中的每个页面,则需要编写 example.com/,仅编写 example.com 是不够的。
  4. \n
  5. 请参阅 了解和配置 Cloudflare 页面规则 了解有关页面规则模式的更多详细信息。
  6. \n
\n
\n

6. 配置 SSL(不必要)

\n

📢 Update 2022.09.05:这一步不是必要的,这里仅供参考!

\n
    \n
  1. 申请 www.example.com 域名的 SSL 证书;
  2. \n
  3. 把 DNS 验证域名的记录添加到 Cloudfare 的 DNS 中;
  4. \n
\n

image.png
\nimage.png
\nimage.png

\n

注意:
\nimage.png

\n

参考资料

\n
    \n
  1. nginx 实现两个域名之间跳转配置 - SegmentFault 思否
  2. \n
  3. 智能云解析 DNS - 通过 Nginx 实现 URL 转发 | 百度智能云文档
  4. \n
  5. SEO 的 301 重定向:你需要知道的一切
  6. \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '语雀'}]}, 'comments': {'nodes': []}}, {'title': 'Python 导出公众号文章为 Markdown', 'number': 7, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/7', 'createdAt': '2023-10-19T03:21:58Z', 'lastEditedAt': '2023-10-19T03:32:09Z', 'updatedAt': '2023-10-19T03:32:09Z', 'body': '记录一下个人使用 Python3 爬取个人公众号的所有文章,并把文章保存为 Markdown 格式的一些操作记录,主要介绍一下思路和一些简单的代码。\r\n\r\n\r\n\r\n## 前提条件与思路\r\n\r\n1. 需要登录网页端微信公众号,获取对应 Cookies;\r\n2. 通过获取的 Cookies 爬取所有的文章 url 以及其他信息;\r\n3. 通过文章 url 获取对应文章的 HTML;\r\n4. 最后,把 HTML 转化为 Markdown。\r\n\r\n之所以选择通过文章公开访问的 url 爬取对应文章的 HTML,而不是直接沿用 Cookies,主要是怕 Cookies 滥用导致其他不可预知的问题,例如封号之类。截止本文章发布前,个人公众号全部已发表的文章大约有 400 多篇,通过这个方法都能正常爬取下来。\r\n\r\n## 获取已发表文章数\r\n\r\n登录公众号,按下 F12 打开开发者工具,在 `网络` 栏中找到 `appmsgpublish` 名称的请求。\r\n\r\n- 查看请求地址\r\n ![appmsgpublish url](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/Gitbook/wechat_url.png)\r\n\r\n- 获取 cookie\r\n ![wecaht cookie](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/Gitbook/wecaht_cookie.png)\r\n\r\n```python\r\nimport requests, json\r\n\r\n#注意把 替换成你自己的 cookie\r\nheaders = {\'Content-type\': \'application/json\', \'User-Agent\': \'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36\',\r\n \'Cookie\': }\r\n\r\n#这个 url 即截图中的请求地址\r\nurl = \'https://mp.weixin.qq.com/cgi-bin/appmsgpublish?sub=list&search_field=null&begin=0&count=5&query=&type=101_1&free_publish_type=1&sub_action=list_ex&token=&lang=zh_CN&f=json&ajax=1\'\r\nreq = requests.get(url, headers=headers)\r\nreq_json = json.loads(req.content.decode("utf-8"))\r\nreq_json\r\n# total_count 即为已发表文章的总数\r\n```\r\n![Wecaht posts total_count](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/Gitbook/total_count.png)\r\n\r\n## 获取所有的文章信息\r\n\r\n以下程序的 `mp.txt` 就是得到的该公众号所有文章信息的列表。\r\n\r\n```python\r\nallPostList = []\r\n\r\nfor number in range(0, 420, 20):\r\n #注意 begin={number}&count=20,即按照每页20篇文章,分页进行爬取\r\n #根据测试每页最多只支持20篇文章\r\n url = f"https://mp.weixin.qq.com/cgi-bin/appmsgpublish?sub=list&search_field=null&begin={number}&count=20&query=&type=101_1&free_publish_type=1&sub_action=list_ex&token=&lang=zh_CN&f=json&ajax=1\', headers=headers)"\r\n x = requests.get(url, headers=headers)\r\n posts_list = json.loads(json.loads(x.content.decode("utf-8"))[\'publish_page\'])["publish_list"]\r\n allPostList = allPostList + posts_list \r\n time.sleep(5)\r\n\r\nwith open("mp.txt", "w") as OUT:\r\n OUT.write(str(allPostList))\r\n```\r\n\r\n## HTML to Markdown\r\n\r\nPython 导出公众号文章为 Markdown 最后的一步工作就是解析上一步骤得到的 `mp.txt` 文件,然后通过 url 去逐一爬取对应的文章 HTML,然后把 Html 转化成 Markdown 即可。\r\n\r\n这些步骤都很简单,网上搜一下就有一大堆教程,感兴趣的可以去搜一下,这里文章就不写了。 \r\n\r\n', 'bodyText': '记录一下个人使用 Python3 爬取个人公众号的所有文章,并把文章保存为 Markdown 格式的一些操作记录,主要介绍一下思路和一些简单的代码。\n\n前提条件与思路\n\n需要登录网页端微信公众号,获取对应 Cookies;\n通过获取的 Cookies 爬取所有的文章 url 以及其他信息;\n通过文章 url 获取对应文章的 HTML;\n最后,把 HTML 转化为 Markdown。\n\n之所以选择通过文章公开访问的 url 爬取对应文章的 HTML,而不是直接沿用 Cookies,主要是怕 Cookies 滥用导致其他不可预知的问题,例如封号之类。截止本文章发布前,个人公众号全部已发表的文章大约有 400 多篇,通过这个方法都能正常爬取下来。\n获取已发表文章数\n登录公众号,按下 F12 打开开发者工具,在 网络 栏中找到 appmsgpublish 名称的请求。\n\n\n查看请求地址\n\n\n\n获取 cookie\n\n\n\nimport requests, json\n\n#注意把 替换成你自己的 cookie\nheaders = {\'Content-type\': \'application/json\', \'User-Agent\': \'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36\',\n \'Cookie\': }\n\n#这个 url 即截图中的请求地址\nurl = \'https://mp.weixin.qq.com/cgi-bin/appmsgpublish?sub=list&search_field=null&begin=0&count=5&query=&type=101_1&free_publish_type=1&sub_action=list_ex&token=&lang=zh_CN&f=json&ajax=1\'\nreq = requests.get(url, headers=headers)\nreq_json = json.loads(req.content.decode("utf-8"))\nreq_json\n# total_count 即为已发表文章的总数\n\n获取所有的文章信息\n以下程序的 mp.txt 就是得到的该公众号所有文章信息的列表。\nallPostList = []\n\nfor number in range(0, 420, 20):\n #注意 begin={number}&count=20,即按照每页20篇文章,分页进行爬取\n #根据测试每页最多只支持20篇文章\n url = f"https://mp.weixin.qq.com/cgi-bin/appmsgpublish?sub=list&search_field=null&begin={number}&count=20&query=&type=101_1&free_publish_type=1&sub_action=list_ex&token=&lang=zh_CN&f=json&ajax=1\', headers=headers)"\n x = requests.get(url, headers=headers)\n posts_list = json.loads(json.loads(x.content.decode("utf-8"))[\'publish_page\'])["publish_list"]\n allPostList = allPostList + posts_list \n time.sleep(5)\n\nwith open("mp.txt", "w") as OUT:\n OUT.write(str(allPostList))\nHTML to Markdown\nPython 导出公众号文章为 Markdown 最后的一步工作就是解析上一步骤得到的 mp.txt 文件,然后通过 url 去逐一爬取对应的文章 HTML,然后把 Html 转化成 Markdown 即可。\n这些步骤都很简单,网上搜一下就有一大堆教程,感兴趣的可以去搜一下,这里文章就不写了。', 'bodyHTML': '

记录一下个人使用 Python3 爬取个人公众号的所有文章,并把文章保存为 Markdown 格式的一些操作记录,主要介绍一下思路和一些简单的代码。

\n\n

前提条件与思路

\n
    \n
  1. 需要登录网页端微信公众号,获取对应 Cookies;
  2. \n
  3. 通过获取的 Cookies 爬取所有的文章 url 以及其他信息;
  4. \n
  5. 通过文章 url 获取对应文章的 HTML;
  6. \n
  7. 最后,把 HTML 转化为 Markdown。
  8. \n
\n

之所以选择通过文章公开访问的 url 爬取对应文章的 HTML,而不是直接沿用 Cookies,主要是怕 Cookies 滥用导致其他不可预知的问题,例如封号之类。截止本文章发布前,个人公众号全部已发表的文章大约有 400 多篇,通过这个方法都能正常爬取下来。

\n

获取已发表文章数

\n

登录公众号,按下 F12 打开开发者工具,在 网络 栏中找到 appmsgpublish 名称的请求。

\n
    \n
  • \n

    查看请求地址
    \nappmsgpublish url

    \n
  • \n
  • \n

    获取 cookie
    \nwecaht cookie

    \n
  • \n
\n
import requests, json\n\n#注意把 <Your Cookie> 替换成你自己的 cookie\nheaders = {\'Content-type\': \'application/json\', \'User-Agent\': \'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36\',\n           \'Cookie\': <Your Cookie>}\n\n#这个 url 即截图中的请求地址\nurl = \'https://mp.weixin.qq.com/cgi-bin/appmsgpublish?sub=list&search_field=null&begin=0&count=5&query=&type=101_1&free_publish_type=1&sub_action=list_ex&token=<token>&lang=zh_CN&f=json&ajax=1\'\nreq = requests.get(url, headers=headers)\nreq_json = json.loads(req.content.decode("utf-8"))\nreq_json\n# total_count 即为已发表文章的总数
\n

Wecaht posts total_count

\n

获取所有的文章信息

\n

以下程序的 mp.txt 就是得到的该公众号所有文章信息的列表。

\n
allPostList = []\n\nfor number in range(0, 420, 20):\n    #注意 begin={number}&count=20,即按照每页20篇文章,分页进行爬取\n    #根据测试每页最多只支持20篇文章\n    url = f"https://mp.weixin.qq.com/cgi-bin/appmsgpublish?sub=list&search_field=null&begin={number}&count=20&query=&type=101_1&free_publish_type=1&sub_action=list_ex&token=<token>&lang=zh_CN&f=json&ajax=1\', headers=headers)"\n    x = requests.get(url, headers=headers)\n    posts_list  = json.loads(json.loads(x.content.decode("utf-8"))[\'publish_page\'])["publish_list"]\n    allPostList = allPostList + posts_list  \n    time.sleep(5)\n\nwith open("mp.txt", "w") as OUT:\n    OUT.write(str(allPostList))
\n

HTML to Markdown

\n

Python 导出公众号文章为 Markdown 最后的一步工作就是解析上一步骤得到的 mp.txt 文件,然后通过 url 去逐一爬取对应的文章 HTML,然后把 Html 转化成 Markdown 即可。

\n

这些步骤都很简单,网上搜一下就有一大堆教程,感兴趣的可以去搜一下,这里文章就不写了。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '2023年下半年的一些乱弹', 'number': 6, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/6', 'createdAt': '2023-10-18T02:46:03Z', 'lastEditedAt': '2023-11-29T01:09:10Z', 'updatedAt': '2023-11-29T01:09:10Z', 'body': '其实写这边文章,主要是想着测试一下使用了 GitHub Actions 的 mkdocs 触发 Discussions to mkdocs blog posts 的一些效果。\r\n\r\n\r\n\r\n今天的天气真好啊!阳光明媚,微风拂面,仿佛是一幅美丽的画卷。这样的天气让人心情愉悦,忍不住想要出去走走,感受大自然的美丽。无论是散步还是骑自行车,都是不错的选择。我享受着这美好的一天,也期待着未来更多美好的时光。\r\n\r\n从 11 月起,公司也好,家庭也罢,陆陆续续的一些事情让生活变得此起彼伏。缺乏了一些码字的动力,整个人变得有点沮丧,空洞夹杂着混沌的状态让整个人都很显得颓废。生活需要激情,希望接下来的 12 月能回归一个更好的状态吧!', 'bodyText': '其实写这边文章,主要是想着测试一下使用了 GitHub Actions 的 mkdocs 触发 Discussions to mkdocs blog posts 的一些效果。\n\n今天的天气真好啊!阳光明媚,微风拂面,仿佛是一幅美丽的画卷。这样的天气让人心情愉悦,忍不住想要出去走走,感受大自然的美丽。无论是散步还是骑自行车,都是不错的选择。我享受着这美好的一天,也期待着未来更多美好的时光。\n从 11 月起,公司也好,家庭也罢,陆陆续续的一些事情让生活变得此起彼伏。缺乏了一些码字的动力,整个人变得有点沮丧,空洞夹杂着混沌的状态让整个人都很显得颓废。生活需要激情,希望接下来的 12 月能回归一个更好的状态吧!', 'bodyHTML': '

其实写这边文章,主要是想着测试一下使用了 GitHub Actions 的 mkdocs 触发 Discussions to mkdocs blog posts 的一些效果。

\n\n

今天的天气真好啊!阳光明媚,微风拂面,仿佛是一幅美丽的画卷。这样的天气让人心情愉悦,忍不住想要出去走走,感受大自然的美丽。无论是散步还是骑自行车,都是不错的选择。我享受着这美好的一天,也期待着未来更多美好的时光。

\n

从 11 月起,公司也好,家庭也罢,陆陆续续的一些事情让生活变得此起彼伏。缺乏了一些码字的动力,整个人变得有点沮丧,空洞夹杂着混沌的状态让整个人都很显得颓废。生活需要激情,希望接下来的 12 月能回归一个更好的状态吧!

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': [{'body': 'Hello,Wed Oct 18 10:46:41 CST 2023', 'author': {'login': 'shenweiyan'}}]}}, {'title': '友情链接', 'number': 5, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/5', 'createdAt': '2023-10-16T07:57:49Z', 'lastEditedAt': '2024-11-05T07:13:09Z', 'updatedAt': '2024-11-05T07:13:09Z', 'body': '> 每一个独立博客都是一个信息孤岛。我们没有类似「你可能喜欢其他人写的这些文章」的推荐机制,所以除了搜索引擎、社交网络引荐之外,我们应该还需要通过某种方法将这些信息孤岛连接起来:**交换友情链接就是一种很棒的架桥方式。**\r\n\r\n社交就是不断认识新的人、结交新的朋友,而友链也正是这样一种很棒的交朋友的方式,作为一个不太善于言辞的技术人,我希望结交更多的朋友,来丰富我的社交,一起成长。\r\n\r\n## 站点信息\r\n\r\n交换友链前可先添加个人站点,站点信息如下。\r\n\r\n- 站点名称: 维燕的知识花园\r\n- 站点链接: \r\n- 站点头像: \r\n- 站点描述: Bio & IT 爱好者,沉淀生活,记录点滴。\r\n\r\n## 交换友链\r\n\r\n想和我交换友链的,没啥特别需求,只是希望你的博客有足够多的**原创**、**有意义**的内容,并且建站已满半年。\r\n\r\n- 那种塞满了转载文章的采集站点暂时不考虑。\r\n- 非常反感很多论坛上动不动就来交换友链的帖子,如果是出于 SEO 的一些目的来交换友链其实是没什么意义的。\r\n\r\n## 友链说明\r\n\r\n如需申请,在下方评论区提供你的「博客名称」和「博客地址」即可。或者参考以下格式:\r\n\r\n- 博客名称:xxxxx\r\n- 博客地址:https://xxxx.com\r\n- 博客介绍:xxxxxxxx\r\n\r\n## 友情站点\r\n\r\n以下站点按照添加的时间顺序排列。\r\n\r\n
\r\n\r\n- __[UncleCAT4](https://yuanj.top/)__\r\n\r\n 思绪来得快去得也快,偶尔会在这里停留。\r\n\r\n- __[1874’s Blog](https://blog.1874.cool)__\r\n\r\n 有粤语歌就不会有世界末日。\r\n\r\n- __[望薮](https://ralvines.top)__\r\n\r\n 以我观物,故物皆著我之色彩。\r\n\r\n- __[Jayden\'s site](https://xxu.do/)__\r\n\r\n 为天地立心,为生民立命,为往圣继绝学,为万世开太平。\r\n\r\n- __[Shitao Wu | 吴诗涛](https://shitao5.org/)__\r\n\r\n 喜欢捣鼓电脑,UseR,喜欢[阅读](https://shitao5.org/tags/%E8%AF%BB%E5%90%8E%E6%84%9F/),重度使用 Kindle。甘愿做一个平庸的人,走在成为我自己的道路上。\r\n\r\n- __[椒盐豆豉](https://blog.douchi.space/)__\r\n\r\n 一个写了二十年博客,现居美国西雅图的女博主+码农。\r\n\r\n- __[墨迹心空](https://www.secondlife.love/)__\r\n\r\n Life is coding.\r\n\r\n- __[言成的个人博客](https://meethigher.top/)__\r\n\r\n 言成的个人博客网站,寓意为让我们相逢在更高处。\r\n\r\n- __[Pepper的博客](https://uioqps.github.io/)__\r\n\r\n 生命留给有价值的事物才能创造价值。\r\n\r\n- __[LINUX DO](https://linux.do/?source=weiyan_cc)__\r\n\r\n 新的理想型社区。\r\n\r\n
', 'bodyText': "每一个独立博客都是一个信息孤岛。我们没有类似「你可能喜欢其他人写的这些文章」的推荐机制,所以除了搜索引擎、社交网络引荐之外,我们应该还需要通过某种方法将这些信息孤岛连接起来:交换友情链接就是一种很棒的架桥方式。\n\n社交就是不断认识新的人、结交新的朋友,而友链也正是这样一种很棒的交朋友的方式,作为一个不太善于言辞的技术人,我希望结交更多的朋友,来丰富我的社交,一起成长。\n站点信息\n交换友链前可先添加个人站点,站点信息如下。\n\n站点名称: 维燕的知识花园\n站点链接: https://weiyan.cc\n站点头像: https://weiyan.cc/assets/logo.png\n站点描述: Bio & IT 爱好者,沉淀生活,记录点滴。\n\n交换友链\n想和我交换友链的,没啥特别需求,只是希望你的博客有足够多的原创、有意义的内容,并且建站已满半年。\n\n那种塞满了转载文章的采集站点暂时不考虑。\n非常反感很多论坛上动不动就来交换友链的帖子,如果是出于 SEO 的一些目的来交换友链其实是没什么意义的。\n\n友链说明\n如需申请,在下方评论区提供你的「博客名称」和「博客地址」即可。或者参考以下格式:\n\n博客名称:xxxxx\n博客地址:https://xxxx.com\n博客介绍:xxxxxxxx\n\n友情站点\n以下站点按照添加的时间顺序排列。\n\n\n\nUncleCAT4\n思绪来得快去得也快,偶尔会在这里停留。\n\n\n1874’s Blog\n有粤语歌就不会有世界末日。\n\n\n望薮\n以我观物,故物皆著我之色彩。\n\n\nJayden's site\n为天地立心,为生民立命,为往圣继绝学,为万世开太平。\n\n\nShitao Wu | 吴诗涛\n喜欢捣鼓电脑,UseR,喜欢阅读,重度使用 Kindle。甘愿做一个平庸的人,走在成为我自己的道路上。\n\n\n椒盐豆豉\n一个写了二十年博客,现居美国西雅图的女博主+码农。\n\n\n墨迹心空\nLife is coding.\n\n\n言成的个人博客\n言成的个人博客网站,寓意为让我们相逢在更高处。\n\n\nPepper的博客\n生命留给有价值的事物才能创造价值。\n\n\nLINUX DO\n新的理想型社区。", 'bodyHTML': '
\n

每一个独立博客都是一个信息孤岛。我们没有类似「你可能喜欢其他人写的这些文章」的推荐机制,所以除了搜索引擎、社交网络引荐之外,我们应该还需要通过某种方法将这些信息孤岛连接起来:交换友情链接就是一种很棒的架桥方式。

\n
\n

社交就是不断认识新的人、结交新的朋友,而友链也正是这样一种很棒的交朋友的方式,作为一个不太善于言辞的技术人,我希望结交更多的朋友,来丰富我的社交,一起成长。

\n

站点信息

\n

交换友链前可先添加个人站点,站点信息如下。

\n\n

交换友链

\n

想和我交换友链的,没啥特别需求,只是希望你的博客有足够多的原创有意义的内容,并且建站已满半年。

\n
    \n
  • 那种塞满了转载文章的采集站点暂时不考虑。
  • \n
  • 非常反感很多论坛上动不动就来交换友链的帖子,如果是出于 SEO 的一些目的来交换友链其实是没什么意义的。
  • \n
\n

友链说明

\n

如需申请,在下方评论区提供你的「博客名称」和「博客地址」即可。或者参考以下格式:

\n
    \n
  • 博客名称:xxxxx
  • \n
  • 博客地址:https://xxxx.com
  • \n
  • 博客介绍:xxxxxxxx
  • \n
\n

友情站点

\n

以下站点按照添加的时间顺序排列。

\n
\n
    \n
  • \n

    UncleCAT4

    \n

    思绪来得快去得也快,偶尔会在这里停留。

    \n
  • \n
  • \n

    1874’s Blog

    \n

    有粤语歌就不会有世界末日。

    \n
  • \n
  • \n

    望薮

    \n

    以我观物,故物皆著我之色彩。

    \n
  • \n
  • \n

    Jayden\'s site

    \n

    为天地立心,为生民立命,为往圣继绝学,为万世开太平。

    \n
  • \n
  • \n

    Shitao Wu | 吴诗涛

    \n

    喜欢捣鼓电脑,UseR,喜欢阅读,重度使用 Kindle。甘愿做一个平庸的人,走在成为我自己的道路上。

    \n
  • \n
  • \n

    椒盐豆豉

    \n

    一个写了二十年博客,现居美国西雅图的女博主+码农。

    \n
  • \n
  • \n

    墨迹心空

    \n

    Life is coding.

    \n
  • \n
  • \n

    言成的个人博客

    \n

    言成的个人博客网站,寓意为让我们相逢在更高处。

    \n
  • \n
  • \n

    Pepper的博客

    \n

    生命留给有价值的事物才能创造价值。

    \n
  • \n
  • \n

    LINUX DO

    \n

    新的理想型社区。

    \n
  • \n
\n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '0.1-站点'}, 'labels': {'nodes': []}, 'comments': {'nodes': [{'body': '**我的站点信息** \r\n\r\n- 站点名称: 维燕的知识花园\r\n- 站点链接: https://weiyan.cc\r\n- 站点头像: https://weiyan.cc/assets/logo.png\r\n- 站点描述: Bio & IT 爱好者,沉淀生活,记录点滴。', 'author': {'login': 'shenweiyan'}}, {'body': '博客名称:Jayden\n博客地址:https://xxu.do\n博客介绍为天地立心,为生民立命, 为往圣继绝学,为万世开太平。\n', 'author': {'login': 'Jaaayden'}}, {'body': 'hello', 'author': {'login': 'vbskycn'}}, {'body': '站名:墨迹心空\n站点链接:https://www.secondlife.love\n站点介绍:life is coding', 'author': {'login': 'secondlife1127'}}, {'body': '你好,uioqps.github.io\n可以交流下技术相关的问题吗', 'author': {'login': 'uioQPS'}}]}}, {'title': '关于 | 作者与站点', 'number': 4, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/4', 'createdAt': '2023-10-16T05:11:48Z', 'lastEditedAt': '2024-08-16T01:32:02Z', 'updatedAt': '2024-08-16T01:32:02Z', 'body': '聊一聊关于作者和这个站点的一些事情。\r\n\r\n## 缘起\r\n\r\n程序员都有一个博客梦,对我来说,写写字也可以成为我调解压力的一个很好方式。\r\n\r\n在独立博客或者说独立站点前,一直有一种 "背靠大树好乘凉" 的心理把自己的文档建立的大平台的服务上,从开源中国、蚂蚁笔记、博客园、简书、CSDN、语雀上踩过不少坑后终于认识到数据可控和 DIY 的好处,于是有了独立博客站点的想法。\r\n\r\n静态博客站点一直是个人最情有独钟的选择,省去了服务器折腾续费运维的种种麻烦,可以更加专注于文字本身的写作。也曾经纠结过 Jekyll、Hexo、Hugo 的选型,但最终被 Hugo 极快的页面编译生成速度所折服,并深受[谢益辉](https://github.com/yihui)前期的 [ivy-hugo-theme](https://github.com/shenweiyan/ivy-hugo-theme) 博客风格影响,自己倒腾了一个 [ICS-Hugo-Theme](https://github.com/shenweiyan/ICS-Hugo-Theme) 用了好几年。\r\n\r\n## 语雀\r\n\r\n在独立博客站点前不得不把语雀单独拎出来说一下。\r\n\r\n从 2018 到 2023 年,语雀一直都是我重度使用的主力平台,没有之一。我也一度以为语雀会成为了未来 5-10 年的主力平台(由于[语雀天使](https://weiyan.cc/note/2021-10-14-yuque-vip/)的福利,我的语雀会员也延长到了 **2037** 年!),[All in Yuque](https://www.yuque.com/shenweiyan/notebook/all-in-yuque) 也成为了我那一段时间的坚持。不幸的是,语雀在 2023 年发生了非常严重的[宕机事件](https://www.zhihu.com/question/627448953),加上前一年沸沸扬扬的[收费事件](https://www.zhihu.com/question/562238887),以及语雀固有的一些问题,对于语雀的信任开始动摇。\r\n\r\n直至 2023 年由于工作地点的变更,加上某些不可描述的原因导致语雀在办公网络下无法直接访问,终于把继续使用语雀的最后一根稻草压垮,逐步开始拥抱 GitHub,并在这个全球最大的开源平台上深入摸索。\r\n\r\n## 当下\r\n\r\n正如个人在[语雀花园](https://www.yuque.com/shenweiyan)所说,2023年7月起个人大部分文章已经转移至 [GitHub](https://github.com/shenweiyan),并同步至 [Knowledge-Garden](https://github.com/shenweiyan/Knowledge-Garden/) (后期主要在 [Discussions](https://github.com/shenweiyan/Knowledge-Garden/discussions) 和 [知识花园](https://weiyan.cc/) 进行写作与更新),语雀会保持不定期更新(基本已经停更)!\r\n\r\n现在的这个站点是基于 [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/) 进行部署,并整合了个人 **[语雀知识库](https://www.yuque.com/shenweiyan)** 几个主要知识库文章后形成的独立站点。\r\n\r\n## 未来\r\n\r\n我希望 [WeiYan.CC](https://weiyan.cc/) 能成为我知识管理的最后一站,虽然未来这些文章展现的形式,或者选择用于部署的技术有所改变,但至少域名是不变的(除非我能有幸注册到 com/cn/net/org 其中之一的主流域名),通过这个域名你至少还能找到曾经我写下的那些字。\r\n\r\n不忘初心,方得始终,希望下一个十年,还能在这里遇到一个曾经的我,看到曾经的文字。\r\n\r\n## 作者\r\n\r\n沈维燕(史提芬先森/章鱼猫先生),一个 90 后的广东人,熟悉粤语、国语,略懂英语。\r\n\r\n- 毕业于南方医科大学(原中国人民解放军第一军医大学)基础医学院生物信息学专业。\r\n- 现工作生活于广州,主要从事 BIO & IT 的一些相关工作。\r\n- 平时喜欢逛逛技术论坛,玩玩羽毛球,看看电影,瞎折腾一下技术。\r\n- 不务正业之余喜欢记录一些生活工作学习中的一些想法。\r\n- 乐于分享,喜欢把事情简单化,程序化。\r\n\r\n## 联系\r\n\r\n个人目前用的比较多的沟通工具,一个是**邮箱**,另外一个是**微信**,你可以通过这两种方式直接和我联系。\r\n\r\n- 邮箱:(或者 )\r\n- 微信:ishenweiyan(添加微信好友,请注明真实姓名)\r\n\r\n!!! tip "请备注真名实姓,让我感受到一个真实的人的气息"\r\n 如果给我发**邮件**,或者通过**微信添加好友**,请写上您的**真名实姓**,让我感受到一个**真实的人**的气息。我不太愿意跟**网名**打交道,对于那些不知来路、上来就问问题的微信和邮件,我通常会直接忽略。', 'bodyText': '聊一聊关于作者和这个站点的一些事情。\n缘起\n程序员都有一个博客梦,对我来说,写写字也可以成为我调解压力的一个很好方式。\n在独立博客或者说独立站点前,一直有一种 "背靠大树好乘凉" 的心理把自己的文档建立的大平台的服务上,从开源中国、蚂蚁笔记、博客园、简书、CSDN、语雀上踩过不少坑后终于认识到数据可控和 DIY 的好处,于是有了独立博客站点的想法。\n静态博客站点一直是个人最情有独钟的选择,省去了服务器折腾续费运维的种种麻烦,可以更加专注于文字本身的写作。也曾经纠结过 Jekyll、Hexo、Hugo 的选型,但最终被 Hugo 极快的页面编译生成速度所折服,并深受谢益辉前期的 ivy-hugo-theme 博客风格影响,自己倒腾了一个 ICS-Hugo-Theme 用了好几年。\n语雀\n在独立博客站点前不得不把语雀单独拎出来说一下。\n从 2018 到 2023 年,语雀一直都是我重度使用的主力平台,没有之一。我也一度以为语雀会成为了未来 5-10 年的主力平台(由于语雀天使的福利,我的语雀会员也延长到了 2037 年!),All in Yuque 也成为了我那一段时间的坚持。不幸的是,语雀在 2023 年发生了非常严重的宕机事件,加上前一年沸沸扬扬的收费事件,以及语雀固有的一些问题,对于语雀的信任开始动摇。\n直至 2023 年由于工作地点的变更,加上某些不可描述的原因导致语雀在办公网络下无法直接访问,终于把继续使用语雀的最后一根稻草压垮,逐步开始拥抱 GitHub,并在这个全球最大的开源平台上深入摸索。\n当下\n正如个人在语雀花园所说,2023年7月起个人大部分文章已经转移至 GitHub,并同步至 Knowledge-Garden (后期主要在 Discussions 和 知识花园 进行写作与更新),语雀会保持不定期更新(基本已经停更)!\n现在的这个站点是基于 Material for MkDocs 进行部署,并整合了个人 语雀知识库 几个主要知识库文章后形成的独立站点。\n未来\n我希望 WeiYan.CC 能成为我知识管理的最后一站,虽然未来这些文章展现的形式,或者选择用于部署的技术有所改变,但至少域名是不变的(除非我能有幸注册到 com/cn/net/org 其中之一的主流域名),通过这个域名你至少还能找到曾经我写下的那些字。\n不忘初心,方得始终,希望下一个十年,还能在这里遇到一个曾经的我,看到曾经的文字。\n作者\n沈维燕(史提芬先森/章鱼猫先生),一个 90 后的广东人,熟悉粤语、国语,略懂英语。\n\n毕业于南方医科大学(原中国人民解放军第一军医大学)基础医学院生物信息学专业。\n现工作生活于广州,主要从事 BIO & IT 的一些相关工作。\n平时喜欢逛逛技术论坛,玩玩羽毛球,看看电影,瞎折腾一下技术。\n不务正业之余喜欢记录一些生活工作学习中的一些想法。\n乐于分享,喜欢把事情简单化,程序化。\n\n联系\n个人目前用的比较多的沟通工具,一个是邮箱,另外一个是微信,你可以通过这两种方式直接和我联系。\n\n邮箱:shen@weiyan.cc(或者 shen@weiyan.tech)\n微信:ishenweiyan(添加微信好友,请注明真实姓名)\n\n!!! tip "请备注真名实姓,让我感受到一个真实的人的气息"\n如果给我发邮件,或者通过微信添加好友,请写上您的真名实姓,让我感受到一个真实的人的气息。我不太愿意跟网名打交道,对于那些不知来路、上来就问问题的微信和邮件,我通常会直接忽略。', 'bodyHTML': '

聊一聊关于作者和这个站点的一些事情。

\n

缘起

\n

程序员都有一个博客梦,对我来说,写写字也可以成为我调解压力的一个很好方式。

\n

在独立博客或者说独立站点前,一直有一种 "背靠大树好乘凉" 的心理把自己的文档建立的大平台的服务上,从开源中国、蚂蚁笔记、博客园、简书、CSDN、语雀上踩过不少坑后终于认识到数据可控和 DIY 的好处,于是有了独立博客站点的想法。

\n

静态博客站点一直是个人最情有独钟的选择,省去了服务器折腾续费运维的种种麻烦,可以更加专注于文字本身的写作。也曾经纠结过 Jekyll、Hexo、Hugo 的选型,但最终被 Hugo 极快的页面编译生成速度所折服,并深受谢益辉前期的 ivy-hugo-theme 博客风格影响,自己倒腾了一个 ICS-Hugo-Theme 用了好几年。

\n

语雀

\n

在独立博客站点前不得不把语雀单独拎出来说一下。

\n

从 2018 到 2023 年,语雀一直都是我重度使用的主力平台,没有之一。我也一度以为语雀会成为了未来 5-10 年的主力平台(由于语雀天使的福利,我的语雀会员也延长到了 2037 年!),All in Yuque 也成为了我那一段时间的坚持。不幸的是,语雀在 2023 年发生了非常严重的宕机事件,加上前一年沸沸扬扬的收费事件,以及语雀固有的一些问题,对于语雀的信任开始动摇。

\n

直至 2023 年由于工作地点的变更,加上某些不可描述的原因导致语雀在办公网络下无法直接访问,终于把继续使用语雀的最后一根稻草压垮,逐步开始拥抱 GitHub,并在这个全球最大的开源平台上深入摸索。

\n

当下

\n

正如个人在语雀花园所说,2023年7月起个人大部分文章已经转移至 GitHub,并同步至 Knowledge-Garden (后期主要在 Discussions知识花园 进行写作与更新),语雀会保持不定期更新(基本已经停更)!

\n

现在的这个站点是基于 Material for MkDocs 进行部署,并整合了个人 语雀知识库 几个主要知识库文章后形成的独立站点。

\n

未来

\n

我希望 WeiYan.CC 能成为我知识管理的最后一站,虽然未来这些文章展现的形式,或者选择用于部署的技术有所改变,但至少域名是不变的(除非我能有幸注册到 com/cn/net/org 其中之一的主流域名),通过这个域名你至少还能找到曾经我写下的那些字。

\n

不忘初心,方得始终,希望下一个十年,还能在这里遇到一个曾经的我,看到曾经的文字。

\n

作者

\n

沈维燕(史提芬先森/章鱼猫先生),一个 90 后的广东人,熟悉粤语、国语,略懂英语。

\n
    \n
  • 毕业于南方医科大学(原中国人民解放军第一军医大学)基础医学院生物信息学专业。
  • \n
  • 现工作生活于广州,主要从事 BIO & IT 的一些相关工作。
  • \n
  • 平时喜欢逛逛技术论坛,玩玩羽毛球,看看电影,瞎折腾一下技术。
  • \n
  • 不务正业之余喜欢记录一些生活工作学习中的一些想法。
  • \n
  • 乐于分享,喜欢把事情简单化,程序化。
  • \n
\n

联系

\n

个人目前用的比较多的沟通工具,一个是邮箱,另外一个是微信,你可以通过这两种方式直接和我联系。

\n\n

!!! tip "请备注真名实姓,让我感受到一个真实的人的气息"
\n如果给我发邮件,或者通过微信添加好友,请写上您的真名实姓,让我感受到一个真实的人的气息。我不太愿意跟网名打交道,对于那些不知来路、上来就问问题的微信和邮件,我通常会直接忽略。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '0.1-站点'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'Discussions 3', 'number': 3, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/3', 'createdAt': '2023-10-16T05:03:33Z', 'lastEditedAt': '2023-11-08T08:03:02Z', 'updatedAt': '2023-12-06T01:35:06Z', 'body': 'Wed Nov 8 14:39:48 CST 2023', 'bodyText': 'Wed Nov 8 14:39:48 CST 2023', 'bodyHTML': '

Wed Nov 8 14:39:48 CST 2023

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '公告说明'}, 'labels': {'nodes': []}, 'comments': {'nodes': [{'body': '这里测试一下回复~', 'author': {'login': 'shenweiyan'}}, {'body': '在 Mkdocs 中插入指定的 discussions 以嵌入评论,其中 `data-term` 为对应的 discussions number~\r\n```\r\n\r\n```', 'author': {'login': 'shenweiyan'}}]}}, {'title': '这是一个备用讨论', 'number': 2, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/2', 'createdAt': '2023-10-16T05:03:14Z', 'lastEditedAt': '2023-12-05T06:33:23Z', 'updatedAt': '2023-12-05T06:33:23Z', 'body': '备用讨论', 'bodyText': '备用讨论', 'bodyHTML': '

备用讨论

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '公告说明'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '使用与说明', 'number': 1, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/1', 'createdAt': '2023-10-16T03:18:39Z', 'lastEditedAt': '2024-05-08T02:39:50Z', 'updatedAt': '2024-05-08T02:39:50Z', 'body': '分享一下我的经验。你也可以用 Github Discussions 搭建自己的论坛、博客、个人笔记等。\r\n\r\n## 欢迎订阅\r\n\r\n用户有自主选择权,只看他感兴趣的内容。\r\n\r\n1. 可以点击项目的 Watch 按钮来订阅消息。具体用法请看 [Github - 查看订阅](https://docs.github.com/zh/account-and-profile/managing-subscriptions-and-notifications-on-github/managing-subscriptions-for-activity-on-github/viewing-your-subscriptions)。\r\n watch-discussions\r\n\r\n 2. 也可以只订阅某个讨论。进入某个讨论,点击右边 Notifications 的 Subscribe 按钮。\r\n \r\n 用户可以在 https://github.com/notifications 里看到订阅的新消息。\r\n\r\n\r\n## 👋 Welcome!\r\n We’re using Discussions as a place to connect with other members of our community. We hope that you:\r\n * Ask questions you’re wondering about.\r\n * Share ideas.\r\n * Engage with other community members.\r\n * Welcome others and are open-minded. Remember that this is a community we\r\n build together 💪.\r\n\r\n To get started, comment below with an introduction of yourself and tell us about what you do with this community.\r\n\r\n\r\n\r\n## 本仓库谈论说明\r\n\r\n这里所有的 `Discussion Format` 都是 `Announcement`:Only maintainers and admins can post new discussions in these categories, but anyone can comment and reply. \r\n![Discussion Format](https://kg.weiyan.cc/2023/12/discussion-format.png)\r\n\r\n## 使用讨论 (Discussion)\r\n\r\n### 搜索讨论\r\n\r\n- 版块搜索:在 Discussions 页面的搜索框输入搜索词即可。\r\n- 全局搜索:在最上面的 Github 搜索框输入 `org:shenweiyan 搜索词` 就能搜索所有版块的讨论。比如搜["生信"](https://github.com/search?q=org%3Ashenweiyan+%E7%94%9F%E4%BF%A1&type=discussions)。\r\n \r\n### 排序讨论\r\n\r\n- 可以按时间来排序讨论。 \r\n sort-discussions\r\n \r\n### 使用 Label 筛选讨论\r\n- Label 是可以无限加的。一个讨论可以有多个 Label。 \r\n filter-labels\r\n\r\n- 标记 Label 的好处在于,用户可以在讨论列表里筛选、多选、反选 Label 对应的讨论。 \r\n filter-by-labels\r\n \r\n## 评论\r\n\r\n评论有两种。一种是在别人的评论下继续回复评论。一种是最底下的评论框,这会回复到主线里。\r\n \r\n如果你针对某个评论进行回复,建议在别人的评论下回复,不要回复到主线。这样其他订阅这个讨论的人不会收到消息提醒的干扰。\r\n \r\n## 讨论管理\r\n\r\n### 讨论分类\r\n\r\n讨论分类由项目管理员维护。按需创建。分类根据名称排序。所以加个数字前缀用来控制显示顺序。\r\n\r\n### 删除讨论\r\n\r\n点进讨论详情页,在右侧最底下有个 delete discussion。\r\n\r\n### 迁移讨论\r\n\r\n- Transfer this discussion 功能可以把讨论移到同组织的另一个项目下。 \r\n transfer-discussion\r\n\r\n- 也可以切换讨论分类。 \r\n change-category\r\n\r\n### 置顶讨论\r\n\r\n在讨论详情页面可以选择置到项目 Discussion 的顶部,或者置到讨论分类的顶部。\r\n置顶讨论\r\n\r\n## 周报月报\r\n可以考虑使用 Github Action 自动跑脚本,通过 Github API 来获取 Discussion 的消息。然后自动创建 release,把简报内容写到 release body 里。这样订阅了项目 release 的人就可以收到。 可以单独创建一个项目来管理,避免订阅的人受到干扰。\r\n\r\nGithub Discussion API:\r\n\r\n* https://docs.github.com/en/search-github/searching-on-github/searching-discussions\r\n* https://docs.github.com/en/graphql/guides/using-the-graphql-api-for-discussions#search\r\n* [Discussions API\xa0community/community#43](https://github.com/orgs/community/discussions/43)\r\n\r\n## 数据备份\r\n\r\n可以考虑使用 Github Action 自动跑脚本,通过 Github API 来获取 Discussion 的消息。\r\n \r\n\r\n## 移动端\r\nGithub 有[移动端 App](https://github.com/mobile)。除了不支持 Polls 功能,其他功能都挺好用的。能查看提醒,也能发布新讨论,也能回复评论。\r\n\r\n## 邮件端\r\n消息提醒同时会发到你绑定的邮箱里。你也可以用邮箱来查收。\r\n\r\n## 博文中加评论\r\n\r\n借助 [giscus](https://giscus.app/zh-CN),可以非常方便在文章页中插入指定的 discussions —— 在导出 discussions 的时候,在文章尾部增加类似以下 JavaScript 即可:\r\n```javascript\r\n\r\n```\r\n', 'bodyText': '分享一下我的经验。你也可以用 Github Discussions 搭建自己的论坛、博客、个人笔记等。\n欢迎订阅\n用户有自主选择权,只看他感兴趣的内容。\n\n\n可以点击项目的 Watch 按钮来订阅消息。具体用法请看 Github - 查看订阅。\n\n\n\n也可以只订阅某个讨论。进入某个讨论,点击右边 Notifications 的 Subscribe 按钮。\n用户可以在 https://github.com/notifications 里看到订阅的新消息。\n\n\n\n👋 Welcome!\nWe’re using Discussions as a place to connect with other members of our community. We hope that you:\n\nAsk questions you’re wondering about.\nShare ideas.\nEngage with other community members.\nWelcome others and are open-minded. Remember that this is a community we\nbuild together 💪.\n\nTo get started, comment below with an introduction of yourself and tell us about what you do with this community.\n\n本仓库谈论说明\n这里所有的 Discussion Format 都是 Announcement:Only maintainers and admins can post new discussions in these categories, but anyone can comment and reply.\n\n使用讨论 (Discussion)\n搜索讨论\n\n版块搜索:在 Discussions 页面的搜索框输入搜索词即可。\n全局搜索:在最上面的 Github 搜索框输入 org:shenweiyan 搜索词 就能搜索所有版块的讨论。比如搜"生信"。\n\n排序讨论\n\n可以按时间来排序讨论。\n\n\n使用 Label 筛选讨论\n\n\nLabel 是可以无限加的。一个讨论可以有多个 Label。\n\n\n\n标记 Label 的好处在于,用户可以在讨论列表里筛选、多选、反选 Label 对应的讨论。\n\n\n\n评论\n评论有两种。一种是在别人的评论下继续回复评论。一种是最底下的评论框,这会回复到主线里。\n如果你针对某个评论进行回复,建议在别人的评论下回复,不要回复到主线。这样其他订阅这个讨论的人不会收到消息提醒的干扰。\n讨论管理\n讨论分类\n讨论分类由项目管理员维护。按需创建。分类根据名称排序。所以加个数字前缀用来控制显示顺序。\n删除讨论\n点进讨论详情页,在右侧最底下有个 delete discussion。\n迁移讨论\n\n\nTransfer this discussion 功能可以把讨论移到同组织的另一个项目下。\n\n\n\n也可以切换讨论分类。\n\n\n\n置顶讨论\n在讨论详情页面可以选择置到项目 Discussion 的顶部,或者置到讨论分类的顶部。\n\n周报月报\n可以考虑使用 Github Action 自动跑脚本,通过 Github API 来获取 Discussion 的消息。然后自动创建 release,把简报内容写到 release body 里。这样订阅了项目 release 的人就可以收到。 可以单独创建一个项目来管理,避免订阅的人受到干扰。\nGithub Discussion API:\n\nhttps://docs.github.com/en/search-github/searching-on-github/searching-discussions\nhttps://docs.github.com/en/graphql/guides/using-the-graphql-api-for-discussions#search\nDiscussions API\xa0community/community#43\n\n数据备份\n可以考虑使用 Github Action 自动跑脚本,通过 Github API 来获取 Discussion 的消息。\n移动端\nGithub 有移动端 App。除了不支持 Polls 功能,其他功能都挺好用的。能查看提醒,也能发布新讨论,也能回复评论。\n邮件端\n消息提醒同时会发到你绑定的邮箱里。你也可以用邮箱来查收。\n博文中加评论\n借助 giscus,可以非常方便在文章页中插入指定的 discussions —— 在导出 discussions 的时候,在文章尾部增加类似以下 JavaScript 即可:\n', 'bodyHTML': '

分享一下我的经验。你也可以用 Github Discussions 搭建自己的论坛、博客、个人笔记等。

\n

欢迎订阅

\n

用户有自主选择权,只看他感兴趣的内容。

\n
    \n
  1. \n

    可以点击项目的 Watch 按钮来订阅消息。具体用法请看 Github - 查看订阅
    \nwatch-discussions

    \n
  2. \n
  3. \n

    也可以只订阅某个讨论。进入某个讨论,点击右边 Notifications 的 Subscribe 按钮。

    \n

    用户可以在 https://github.com/notifications 里看到订阅的新消息。

    \n
  4. \n
\n\n

👋 Welcome!

\n

We’re using Discussions as a place to connect with other members of our community. We hope that you:

\n
    \n
  • Ask questions you’re wondering about.
  • \n
  • Share ideas.
  • \n
  • Engage with other community members.
  • \n
  • Welcome others and are open-minded. Remember that this is a community we
    \nbuild together 💪.
  • \n
\n

To get started, comment below with an introduction of yourself and tell us about what you do with this community.

\n\n

本仓库谈论说明

\n

这里所有的 Discussion Format 都是 Announcement:Only maintainers and admins can post new discussions in these categories, but anyone can comment and reply.
\nDiscussion Format

\n

使用讨论 (Discussion)

\n

搜索讨论

\n
    \n
  • 版块搜索:在 Discussions 页面的搜索框输入搜索词即可。
  • \n
  • 全局搜索:在最上面的 Github 搜索框输入 org:shenweiyan 搜索词 就能搜索所有版块的讨论。比如搜"生信"
  • \n
\n

排序讨论

\n
    \n
  • 可以按时间来排序讨论。
    \nsort-discussions
  • \n
\n

使用 Label 筛选讨论

\n
    \n
  • \n

    Label 是可以无限加的。一个讨论可以有多个 Label。
    \nfilter-labels

    \n
  • \n
  • \n

    标记 Label 的好处在于,用户可以在讨论列表里筛选、多选、反选 Label 对应的讨论。
    \nfilter-by-labels

    \n
  • \n
\n

评论

\n

评论有两种。一种是在别人的评论下继续回复评论。一种是最底下的评论框,这会回复到主线里。

\n

如果你针对某个评论进行回复,建议在别人的评论下回复,不要回复到主线。这样其他订阅这个讨论的人不会收到消息提醒的干扰。

\n

讨论管理

\n

讨论分类

\n

讨论分类由项目管理员维护。按需创建。分类根据名称排序。所以加个数字前缀用来控制显示顺序。

\n

删除讨论

\n

点进讨论详情页,在右侧最底下有个 delete discussion。

\n

迁移讨论

\n
    \n
  • \n

    Transfer this discussion 功能可以把讨论移到同组织的另一个项目下。
    \ntransfer-discussion

    \n
  • \n
  • \n

    也可以切换讨论分类。
    \nchange-category

    \n
  • \n
\n

置顶讨论

\n

在讨论详情页面可以选择置到项目 Discussion 的顶部,或者置到讨论分类的顶部。
\n置顶讨论

\n

周报月报

\n

可以考虑使用 Github Action 自动跑脚本,通过 Github API 来获取 Discussion 的消息。然后自动创建 release,把简报内容写到 release body 里。这样订阅了项目 release 的人就可以收到。 可以单独创建一个项目来管理,避免订阅的人受到干扰。

\n

Github Discussion API:

\n\n

数据备份

\n

可以考虑使用 Github Action 自动跑脚本,通过 Github API 来获取 Discussion 的消息。

\n

移动端

\n

Github 有移动端 App。除了不支持 Polls 功能,其他功能都挺好用的。能查看提醒,也能发布新讨论,也能回复评论。

\n

邮件端

\n

消息提醒同时会发到你绑定的邮箱里。你也可以用邮箱来查收。

\n

博文中加评论

\n

借助 giscus,可以非常方便在文章页中插入指定的 discussions —— 在导出 discussions 的时候,在文章尾部增加类似以下 JavaScript 即可:

\n
<script src="https://giscus.app/client.js"\n        data-repo="shenweiyan/Knowledge-Garden"\n        data-repo-id="R_kgDOKgxWlg"\n        data-mapping="number"\n        data-term="4"\n        data-reactions-enabled="1"\n        data-emit-metadata="0"\n        data-input-position="bottom"\n        data-theme="light"\n        data-lang="zh-CN"\n        crossorigin="anonymous"\n        async>\n</script>
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '公告说明'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}]} \ No newline at end of file +{'date': '2024-11-10 03:02:42.732490+08:00', 'nodes': [{'title': 'GitHub Actions 更新 Submodule', 'number': 93, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/93', 'createdAt': '2024-11-06T03:31:21Z', 'lastEditedAt': None, 'updatedAt': '2024-11-06T03:31:22Z', 'body': '怎么通过 GitHub Actions 实时更新 Git 仓库中的子模块(submodules)。\r\n\r\n\r\n\r\n```yaml\r\nname: Send submodule updates to parent repo\r\n\r\non:\r\n push:\r\n branches: \r\n - main\r\n\r\njobs:\r\n update:\r\n runs-on: ubuntu-latest\r\n\r\n steps:\r\n - uses: actions/checkout@v2\r\n with: \r\n repository: xxx/parent_xxx\r\n token: ${{ secrets.PRIVATE_TOKEN_GITHUB }}\r\n\r\n - name: Pull & update submodules recursively\r\n run: |\r\n git submodule update --init --recursive\r\n git submodule update --recursive --remote\r\n - name: Commit\r\n run: |\r\n git config user.email "actions@github.com"\r\n git config user.name "GitHub Actions - update submodules"\r\n git add --all\r\n git commit -m "Update submodules" || echo "No changes to commit"\r\n git push\r\n```\r\n\r\n1. `git submodule update --init --recursive`\r\n\r\n这个命令用于初始化并更新仓库中的子模块。具体来说:\r\n\r\n- `--init` 参数会初始化在 `.gitmodules` 文件中指定的每个子模块的配置信息,但不会更新子模块的内容。这个步骤是必须的,因为 Git 不会自动初始化子模块的配置信息。\r\n- `--recursive` 参数确保命令递归地应用于任何嵌套的子模块。这意味着如果子模块本身还包含子模块,这些子模块也会被初始化。\r\n\r\n简而言之,这个命令会初始化仓库中所有(包括嵌套的)子模块的配置,并更新它们到在父仓库中记录的提交。\r\n\r\n2. `git submodule update --recursive --remote`\r\n\r\n这个命令用于更新仓库中的子模块到它们的远程仓库中的最新状态(或指定的分支/标签)。具体来说:\r\n\r\n- `--recursive` 的作用与上述命令相同,确保命令递归地应用于所有嵌套的子模块。\r\n- `--remot`e 参数指示 Git 更新每个子模块到其远程仓库的当前分支的最新提交。如果没有指定分支,则默认为在 `.gitmodules ` 文件中为每个子模块指定的分支。\r\n\r\n注意,这个命令并不会改变父仓库中记录的子模块的提交。它只是更新了子模块的工作目录和索引,以匹配远程仓库的最新状态。如果你想在父仓库中记录这些更新,你需要在子模块中执行提交,然后回到父仓库中,添加子模块的变更并提交。\r\n\r\n3. 总结\r\n\r\n- `git submodule update --init --recursive` 用于初始化并更新子模块到父仓库中记录的提交。\r\n- `git submodule update --recursive --remote` 用于将子模块更新到其远程仓库的最新状态,但不会在父仓库中记录这些更新。\r\n', 'bodyText': '怎么通过 GitHub Actions 实时更新 Git 仓库中的子模块(submodules)。\n\nname: Send submodule updates to parent repo\n\non:\n push:\n branches: \n - main\n\njobs:\n update:\n runs-on: ubuntu-latest\n\n steps:\n - uses: actions/checkout@v2\n with: \n repository: xxx/parent_xxx\n token: ${{ secrets.PRIVATE_TOKEN_GITHUB }}\n\n - name: Pull & update submodules recursively\n run: |\n git submodule update --init --recursive\n git submodule update --recursive --remote\n - name: Commit\n run: |\n git config user.email "actions@github.com"\n git config user.name "GitHub Actions - update submodules"\n git add --all\n git commit -m "Update submodules" || echo "No changes to commit"\n git push\n\ngit submodule update --init --recursive\n\n这个命令用于初始化并更新仓库中的子模块。具体来说:\n\n--init 参数会初始化在 .gitmodules 文件中指定的每个子模块的配置信息,但不会更新子模块的内容。这个步骤是必须的,因为 Git 不会自动初始化子模块的配置信息。\n--recursive 参数确保命令递归地应用于任何嵌套的子模块。这意味着如果子模块本身还包含子模块,这些子模块也会被初始化。\n\n简而言之,这个命令会初始化仓库中所有(包括嵌套的)子模块的配置,并更新它们到在父仓库中记录的提交。\n\ngit submodule update --recursive --remote\n\n这个命令用于更新仓库中的子模块到它们的远程仓库中的最新状态(或指定的分支/标签)。具体来说:\n\n--recursive 的作用与上述命令相同,确保命令递归地应用于所有嵌套的子模块。\n--remote 参数指示 Git 更新每个子模块到其远程仓库的当前分支的最新提交。如果没有指定分支,则默认为在 .gitmodules 文件中为每个子模块指定的分支。\n\n注意,这个命令并不会改变父仓库中记录的子模块的提交。它只是更新了子模块的工作目录和索引,以匹配远程仓库的最新状态。如果你想在父仓库中记录这些更新,你需要在子模块中执行提交,然后回到父仓库中,添加子模块的变更并提交。\n\n总结\n\n\ngit submodule update --init --recursive 用于初始化并更新子模块到父仓库中记录的提交。\ngit submodule update --recursive --remote 用于将子模块更新到其远程仓库的最新状态,但不会在父仓库中记录这些更新。', 'bodyHTML': '

怎么通过 GitHub Actions 实时更新 Git 仓库中的子模块(submodules)。

\n\n
name: Send submodule updates to parent repo\n\non:\n  push:\n    branches: \n      - main\n\njobs:\n  update:\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v2\n        with: \n          repository: xxx/parent_xxx\n          token: ${{ secrets.PRIVATE_TOKEN_GITHUB }}\n\n      - name: Pull & update submodules recursively\n        run: |\n          git submodule update --init --recursive\n          git submodule update --recursive --remote\n      - name: Commit\n        run: |\n          git config user.email "actions@github.com"\n          git config user.name "GitHub Actions - update submodules"\n          git add --all\n          git commit -m "Update submodules" || echo "No changes to commit"\n          git push
\n
    \n
  1. git submodule update --init --recursive
  2. \n
\n

这个命令用于初始化并更新仓库中的子模块。具体来说:

\n
    \n
  • --init 参数会初始化在 .gitmodules 文件中指定的每个子模块的配置信息,但不会更新子模块的内容。这个步骤是必须的,因为 Git 不会自动初始化子模块的配置信息。
  • \n
  • --recursive 参数确保命令递归地应用于任何嵌套的子模块。这意味着如果子模块本身还包含子模块,这些子模块也会被初始化。
  • \n
\n

简而言之,这个命令会初始化仓库中所有(包括嵌套的)子模块的配置,并更新它们到在父仓库中记录的提交。

\n
    \n
  1. git submodule update --recursive --remote
  2. \n
\n

这个命令用于更新仓库中的子模块到它们的远程仓库中的最新状态(或指定的分支/标签)。具体来说:

\n
    \n
  • --recursive 的作用与上述命令相同,确保命令递归地应用于所有嵌套的子模块。
  • \n
  • --remote 参数指示 Git 更新每个子模块到其远程仓库的当前分支的最新提交。如果没有指定分支,则默认为在 .gitmodules 文件中为每个子模块指定的分支。
  • \n
\n

注意,这个命令并不会改变父仓库中记录的子模块的提交。它只是更新了子模块的工作目录和索引,以匹配远程仓库的最新状态。如果你想在父仓库中记录这些更新,你需要在子模块中执行提交,然后回到父仓库中,添加子模块的变更并提交。

\n
    \n
  1. 总结
  2. \n
\n
    \n
  • git submodule update --init --recursive 用于初始化并更新子模块到父仓库中记录的提交。
  • \n
  • git submodule update --recursive --remote 用于将子模块更新到其远程仓库的最新状态,但不会在父仓库中记录这些更新。
  • \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '1.3.18-版本控制'}]}, 'comments': {'nodes': []}}, {'title': 'Follow 初体验', 'number': 92, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/92', 'createdAt': '2024-10-29T09:10:42Z', 'lastEditedAt': '2024-10-31T03:00:25Z', 'updatedAt': '2024-10-31T03:00:25Z', 'body': '在 2024 年国庆前后的这一段时间,[Follow](https://follow.is/) 的这个号称 Next-Gen Information Browser 的 RSS 阅读器在各大平台相当的火,各种疯抢激活码的帖子也是起此彼伏。直到 10 月 24,开始公测,上去体验了一下,发现也就跟其它 RSS 软件没啥太大区别,并没有说的那么玄乎。\r\n\r\n\r\n\r\n## 卡顿\r\n\r\n有人提到的公测遇到的第一个问题 **"卡"**,加载缓慢。这个问题,我也感受到了,我一直用的 Web 版本,刚开始的时候的确不够流畅。有人说这跟代理工具和节点有关,通过更换工具和节点解决。\r\n\r\n## 解析异常\r\n\r\n一个 RSS 最核心的还是要能订阅并正常获取并解析订阅源的内容。这一点 Follow 给我的感觉不好。在订阅 [袁凡](https://yuanfan.rbind.io/) 老师的博客,就出现了无法正常解析。 \r\n![follow-earfanfan](https://kg.weiyan.cc/2024/10/follow-earfanfan.png)\r\n\r\n同样的订阅,在 [QiReader](https://github.com/shenweiyan/Knowledge-Garden/discussions/73) 上却表现很好。 \r\n![qireader-earfanfan](https://kg.weiyan.cc/2024/10/qireader-earfanfan.png)\r\n\r\n\r\n## 列表赚钱\r\n\r\n> 之前为什么水军这么多到处发订阅列表,今天用了下才知道原来 RSS 列表真的可以赚钱。第一次见到这种创新,和之前的饥饿营销绝配了。然而阅读器本身做得不怎样。 \r\n\r\n很同意这个评论,对于这一种赚钱方式,的确第一次见到。\r\n\r\n## 其他看法\r\n\r\n在细节处理,希望这一款 **Next-Gen Information Browser** 继续打磨。\r\n\r\n![follow-joe-hou](https://kg.weiyan.cc/2024/10/follow-joe-hou.png)', 'bodyText': '在 2024 年国庆前后的这一段时间,Follow 的这个号称 Next-Gen Information Browser 的 RSS 阅读器在各大平台相当的火,各种疯抢激活码的帖子也是起此彼伏。直到 10 月 24,开始公测,上去体验了一下,发现也就跟其它 RSS 软件没啥太大区别,并没有说的那么玄乎。\n\n卡顿\n有人提到的公测遇到的第一个问题 "卡",加载缓慢。这个问题,我也感受到了,我一直用的 Web 版本,刚开始的时候的确不够流畅。有人说这跟代理工具和节点有关,通过更换工具和节点解决。\n解析异常\n一个 RSS 最核心的还是要能订阅并正常获取并解析订阅源的内容。这一点 Follow 给我的感觉不好。在订阅 袁凡 老师的博客,就出现了无法正常解析。\n\n同样的订阅,在 QiReader 上却表现很好。\n\n列表赚钱\n\n之前为什么水军这么多到处发订阅列表,今天用了下才知道原来 RSS 列表真的可以赚钱。第一次见到这种创新,和之前的饥饿营销绝配了。然而阅读器本身做得不怎样。\n\n很同意这个评论,对于这一种赚钱方式,的确第一次见到。\n其他看法\n在细节处理,希望这一款 Next-Gen Information Browser 继续打磨。', 'bodyHTML': '

在 2024 年国庆前后的这一段时间,Follow 的这个号称 Next-Gen Information Browser 的 RSS 阅读器在各大平台相当的火,各种疯抢激活码的帖子也是起此彼伏。直到 10 月 24,开始公测,上去体验了一下,发现也就跟其它 RSS 软件没啥太大区别,并没有说的那么玄乎。

\n\n

卡顿

\n

有人提到的公测遇到的第一个问题 "卡",加载缓慢。这个问题,我也感受到了,我一直用的 Web 版本,刚开始的时候的确不够流畅。有人说这跟代理工具和节点有关,通过更换工具和节点解决。

\n

解析异常

\n

一个 RSS 最核心的还是要能订阅并正常获取并解析订阅源的内容。这一点 Follow 给我的感觉不好。在订阅 袁凡 老师的博客,就出现了无法正常解析。
\nfollow-earfanfan

\n

同样的订阅,在 QiReader 上却表现很好。
\nqireader-earfanfan

\n

列表赚钱

\n
\n

之前为什么水军这么多到处发订阅列表,今天用了下才知道原来 RSS 列表真的可以赚钱。第一次见到这种创新,和之前的饥饿营销绝配了。然而阅读器本身做得不怎样。

\n
\n

很同意这个评论,对于这一种赚钱方式,的确第一次见到。

\n

其他看法

\n

在细节处理,希望这一款 Next-Gen Information Browser 继续打磨。

\n

follow-joe-hou

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'hisat2-build RAM 不足', 'number': 91, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/91', 'createdAt': '2024-10-23T07:39:36Z', 'lastEditedAt': None, 'updatedAt': '2024-10-23T07:39:37Z', 'body': '在 96G RAM 的节点跑 T2T-CHM13v2.0 的 HISAT2 index 时候,发现任务居然被系统 Killed 掉了。\r\n\r\n\r\n\r\n排查一下才发现是因为 RAM 内存不够! \r\n![hisat2-resource-usage-summary](https://kg.weiyan.cc/2024/10/hisat2-resource.png)\r\n\r\n> Note: If you use [--snp](https://open.bioqueue.org/home/knowledge/showKnowledge/sig/hisat2-build#--snp), [--ss](https://open.bioqueue.org/home/knowledge/showKnowledge/sig/hisat2-build#--ss), and/or [--exon](https://open.bioqueue.org/home/knowledge/showKnowledge/sig/hisat2-build#--exon), hisat2-build will need about **200 GB** RAM for the human genome size as index building involves a graph construction. Otherwise, you will be able to build an index on your desktop with 8GB RAM.\r\n> \r\n> From [hisat2-build manual with usage examples | BioQueue Encyclopedia](https://open.bioqueue.org/home/knowledge/showKnowledge/sig/hisat2-build)', 'bodyText': '在 96G RAM 的节点跑 T2T-CHM13v2.0 的 HISAT2 index 时候,发现任务居然被系统 Killed 掉了。\n\n排查一下才发现是因为 RAM 内存不够!\n\n\nNote: If you use --snp, --ss, and/or --exon, hisat2-build will need about 200 GB RAM for the human genome size as index building involves a graph construction. Otherwise, you will be able to build an index on your desktop with 8GB RAM.\nFrom hisat2-build manual with usage examples | BioQueue Encyclopedia', 'bodyHTML': '

在 96G RAM 的节点跑 T2T-CHM13v2.0 的 HISAT2 index 时候,发现任务居然被系统 Killed 掉了。

\n\n

排查一下才发现是因为 RAM 内存不够!
\nhisat2-resource-usage-summary

\n
\n

Note: If you use --snp, --ss, and/or --exon, hisat2-build will need about 200 GB RAM for the human genome size as index building involves a graph construction. Otherwise, you will be able to build an index on your desktop with 8GB RAM.

\n

From hisat2-build manual with usage examples | BioQueue Encyclopedia

\n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.1-生信'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'Galaxy 平台 release_24.x 升级之路', 'number': 90, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/90', 'createdAt': '2024-10-18T02:40:04Z', 'lastEditedAt': '2024-10-21T01:19:17Z', 'updatedAt': '2024-10-21T01:19:17Z', 'body': '记录一下 Galaxy 分析平台从 **release_20.09** 升级到 **release_24.0**,横跨九个发布版本的升级之路。\r\n\r\n\r\n\r\n## 为什么要升级\r\n\r\n很主要的一个原因是随着新技术的更新,旧版本的使用可能会存在一些安全隐患,尤其对于提供互联网公开访问的平台。新版本的升级有助于捕获并应用所有先前的安全更新,以确保平台的安全性。\r\n\r\n## 版本选择\r\n\r\n最开始选择的是 [release_24.1](https://docs.galaxyproject.org/en/master/releases/24.1_announce_user.html) 版本,但好不容易安装完成后才发现,这个新版本中增加了一个常规途径下无法隐藏的 **Activity Bar Interface**,一时间无法忍受。\r\n![23.1-activity-bar](https://kg.weiyan.cc/2024/10/23.1-activity-bar.png) \r\n![galaxy-24.1](https://kg.weiyan.cc/2024/10/galaxy-24.1.png)\r\n\r\n第二个原因是,后台 PostgreSQL 数据库的升级遇到了 [function gen_random_uuid() does not exist](https://help.galaxyproject.org/t/database-upgrade-error/13687) 异常,一下子没法解决也不想去升级 PostgreSQL 版本。\r\n\r\n所以,最终选择了从 **release_20.09** 升级到次新的 **release_24.0** 版本方案。\r\n\r\n## 安装系统环境\r\n\r\n这里以 release_24.1 作为示例,该环境要求同样适用于 release_24.0。\r\n\r\nGalaxy release_24.1 默认安装 node-v18.12.1,参考:`run.sh` → `./scripts/common_startup_functions.sh` → `./scripts/common_startup.sh` → `nodeenv -n "$NODE_VERSION" -p` 的安装代码。\r\n\r\nnode-v18.12.1 下载地址:\r\n\r\nnode-v18.12.1 要求 g++ 8.3.0 or clang++ 8.0.0: \r\n![node-v18.12.1-gcc](https://kg.weiyan.cc/2024/10/node-v18.12.1-gcc.webp)\r\n\r\n可以通过安装 Devtoolset 的方式解决: \r\n\r\n1. 手动调整 CentOS 7 的 SCL YUM 源(也可以 yum 安装),注意变更 `baseurl` 为阿里云或者其他的源链接。\r\n ```bash\r\n # 会默认在 /etc/yum.repos.d 下生成 2 个 repo 源文件\r\n # CentOS-SCLo-scl.repo\r\n # CentOS-SCLo-scl-rh.repo\r\n yum install centos-release-scl centos-release-scl-rh\r\n ```\r\n2. 更新 yum 源的缓存。\r\n ```bash\r\n cd /etc/yum.repos.d\r\n yum clean all\r\n yum makecache\r\n ```\r\n3. 安装 scl-utils,scl-utils 是管理 SCL (Software Collection) 环境设置和运行软件的一套软件工具。\r\n ```bash\r\n yum install scl-utils\r\n ```\r\n4. 安装 devtoolset-9。\r\n ```bash\r\n yum install devtoolset-9\r\n ```\r\n5. 激活 devtoolset-9。\r\n ```bash\r\n source /opt/rh/devtoolset-9/enable\r\n ```\r\n\r\n## Python 环境\r\n\r\nGalaxy 要求 Python >= 3.8,node-v18.12.1 要求 3.6<=Python<=3.10,这里选择 Python-3.9.18,安装如下。\r\n\r\n```bash\r\nwget https://www.python.org/ftp/python/3.9.18/Python-3.9.18.tgz\r\ntar zvxf Python-3.9.18.tgz\r\ncd Python-3.9.18\r\n$enabledevtoolset9\r\nexport TCLTK_LIBS="-L/home/shenweiyan/software/tcltK-8.5.19/lib -ltcl8.5 -ltk8.5"\r\nexport TCLTK_CFLAGS="-I/home/shenweiyan/software/tcltK-8.5.19/include"\r\n./configure --enable-optimizations --prefix=/home/shenweiyan/software/python-3.9.18 --with-openssl=/home/shenweiyan/software/openssl-1.1.1/ --with-tcltk-includes="-I/home/shenweiyan/software/tcltK-8.5.19/include" --with-tcltk-libs="-L/home/shenweiyan/software/tcltK-8.5.19/lib -ltcl8.5 -ltk8.5" \r\nmake -j 4\r\nmake install\r\n```\r\n\r\nPython-3.9.18 安装完成后,避免 `ssl` 模块无法正常 `import` 使用,需要在环境中增加以下设置。\r\n```bash\r\nexport LD_LIBRARY_PATH=/home/shenweiyan/software/openssl-1.1.1/lib:$LD_LIBRARY_PATH\r\n```\r\n\r\n## Node 环境\r\n\r\nGalaxy 的 `sh run.sh` 默认通过 `ssl` 的方式安装已经提前编译好的 node-v18.12.1-linux-x64.tar.gz(直接解压即可使用),对于系统版本比较低的服务器(如 CentOS 7)会存在 GLIBC 异常,因此需要调整为 `ignore_ssl_certs` 的下载方式 + source 源码安装的方式安装 node-v18.12.1。 \r\n![nodeenv--help](https://kg.weiyan.cc/2024/10/nodeenv-help.webp)\r\n\r\n所以,最终的方法为调整 `./scripts/common_startup.sh` 中 `nodeenv -n "$NODE_VERSION" -p` 的安装代码如下:\r\n```bash\r\nnodeenv -n "$NODE_VERSION" -p --source --ignore_ssl_certs --jobs=1\r\n```\r\n\r\nnode-v18.12.1 下载地址:。\r\n\r\n由于编译非常耗时(4核8G 的服务器编译了 1 个小时左右),且对 Python 版本有要求,建议手动安装,具体安装步骤如下。\r\n```bash\r\nshenweiyan@centos-vm-7 10:30:34 /home/shenweiyan/src/node-v18.12.1\r\n$ ./configure --prefix=/home/shenweiyan/software/node-v18.12.1\r\nNode.js configure: Found Python 3.11.6...\r\nPlease use python3.10 or python3.9 or python3.8 or python3.7 or python3.6.\r\n```\r\n\r\n```bash\r\n$ wget https://nodejs.org/download/release/v18.12.1/node-v18.12.1.tar.gz\r\n$ tar zvxf node-v18.12.1.tar.gz\r\n$ cd node-v18.12.1\r\n$ source /opt/rh/devtoolset-9/enable\r\n$ ./configure --prefix=/home/shenweiyan/software/node-v18.12.1\r\nNode.js configure: Found Python 3.9.18...\r\nINFO: configure completed successfully\r\n$ make -j 4\r\n$ make install\r\n```\r\n\r\n## Yarn 环境\r\n\r\n注意要先设置 `npm` 的路径,如果有多个版本的 `npm`,会因为版本混乱导致语法异常。\r\n\r\n```bash\r\nexport PATH=/home/shenweiyan/software/node-v18.12.1/bin:$PATH\r\n/home/shenweiyan/software/node-v18.12.1/bin/npm install --global yarn\r\n```\r\n\r\n## pip 源\r\n\r\nGalaxy 在安装 `requirements.txt` 的时候默认使用下面两个源:\r\n\r\n- \r\n- \r\n\r\n对于国内服务器,可以考虑更换为阿里云或者清华大学的 pip 源。可以:\r\n\r\n- 在 `scripts/common_startup.sh` 中修改:\r\n ```bash\r\n : ${PYPI_INDEX_URL:="https://mirrors.aliyun.com/pypi/simple/"}\r\n ```\r\n\r\n- 在 `requirements.txt` 头部增加:\r\n ```bash\r\n -i https://mirrors.aliyun.com/pypi/simple/\r\n --extra-index-url https://wheels.galaxyproject.org/simple\r\n ```\r\n\r\n## 数据库升级\r\n\r\n这是本次 Galaxy 核心版本升级时候遇到的最大问题。\r\n\r\n由于 Galaxy 在 release_21.05 新增加了一个 [`history_audit`](https://github.com/galaxyproject/galaxy/pull/11914) 数据表,release_20.09 的数据库直接执行 `sh manage_db.sh upgrade` 升级的时候 `history_audit` 数据表并不会一并创建和更新,因此最终导致在 Galaxy 服务启动的时候发生错误。\r\n\r\n这应该是数据库升级时候的一个bug,经过摸索发现,目前可以参考下面的文章,通过分步升级的方式解决。\r\n\r\n- \r\n\r\n以上解决方法,参考:[galaxyproject/galaxy #19016](https://github.com/galaxyproject/galaxy/issues/19016) \r\n \r\n![galaxy-issues-19016](https://kg.weiyan.cc/2024/10/galaxy-issues-19016.png)\r\n\r\n## 总结\r\n\r\n更新后的 release_24.0 界面看起来比旧版本要更加清爽舒服一些,各个页面的汉化功能也有所改善,新增的 Notifications 功能也挺不错,总之升级之后各个方面还是挺满意的,其他细节和功能还在体验中。\r\n', 'bodyText': '记录一下 Galaxy 分析平台从 release_20.09 升级到 release_24.0,横跨九个发布版本的升级之路。\n\n为什么要升级\n很主要的一个原因是随着新技术的更新,旧版本的使用可能会存在一些安全隐患,尤其对于提供互联网公开访问的平台。新版本的升级有助于捕获并应用所有先前的安全更新,以确保平台的安全性。\n版本选择\n最开始选择的是 release_24.1 版本,但好不容易安装完成后才发现,这个新版本中增加了一个常规途径下无法隐藏的 Activity Bar Interface,一时间无法忍受。\n\n\n第二个原因是,后台 PostgreSQL 数据库的升级遇到了 function gen_random_uuid() does not exist 异常,一下子没法解决也不想去升级 PostgreSQL 版本。\n所以,最终选择了从 release_20.09 升级到次新的 release_24.0 版本方案。\n安装系统环境\n这里以 release_24.1 作为示例,该环境要求同样适用于 release_24.0。\nGalaxy release_24.1 默认安装 node-v18.12.1,参考:run.sh → ./scripts/common_startup_functions.sh → ./scripts/common_startup.sh → nodeenv -n "$NODE_VERSION" -p 的安装代码。\nnode-v18.12.1 下载地址:https://nodejs.org/download/release/v18.12.1/\nnode-v18.12.1 要求 g++ 8.3.0 or clang++ 8.0.0:\n\n可以通过安装 Devtoolset 的方式解决:\n\n手动调整 CentOS 7 的 SCL YUM 源(也可以 yum 安装),注意变更 baseurl 为阿里云或者其他的源链接。\n# 会默认在 /etc/yum.repos.d 下生成 2 个 repo 源文件\n# CentOS-SCLo-scl.repo\n# CentOS-SCLo-scl-rh.repo\nyum install centos-release-scl centos-release-scl-rh\n\n更新 yum 源的缓存。\ncd /etc/yum.repos.d\nyum clean all\nyum makecache\n\n安装 scl-utils,scl-utils 是管理 SCL (Software Collection) 环境设置和运行软件的一套软件工具。\nyum install scl-utils\n\n安装 devtoolset-9。\nyum install devtoolset-9\n\n激活 devtoolset-9。\nsource /opt/rh/devtoolset-9/enable\n\n\nPython 环境\nGalaxy 要求 Python >= 3.8,node-v18.12.1 要求 3.6<=Python<=3.10,这里选择 Python-3.9.18,安装如下。\nwget https://www.python.org/ftp/python/3.9.18/Python-3.9.18.tgz\ntar zvxf Python-3.9.18.tgz\ncd Python-3.9.18\n$enabledevtoolset9\nexport TCLTK_LIBS="-L/home/shenweiyan/software/tcltK-8.5.19/lib -ltcl8.5 -ltk8.5"\nexport TCLTK_CFLAGS="-I/home/shenweiyan/software/tcltK-8.5.19/include"\n./configure --enable-optimizations --prefix=/home/shenweiyan/software/python-3.9.18 --with-openssl=/home/shenweiyan/software/openssl-1.1.1/ --with-tcltk-includes="-I/home/shenweiyan/software/tcltK-8.5.19/include" --with-tcltk-libs="-L/home/shenweiyan/software/tcltK-8.5.19/lib -ltcl8.5 -ltk8.5" \nmake -j 4\nmake install\nPython-3.9.18 安装完成后,避免 ssl 模块无法正常 import 使用,需要在环境中增加以下设置。\nexport LD_LIBRARY_PATH=/home/shenweiyan/software/openssl-1.1.1/lib:$LD_LIBRARY_PATH\nNode 环境\nGalaxy 的 sh run.sh 默认通过 ssl 的方式安装已经提前编译好的 node-v18.12.1-linux-x64.tar.gz(直接解压即可使用),对于系统版本比较低的服务器(如 CentOS 7)会存在 GLIBC 异常,因此需要调整为 ignore_ssl_certs 的下载方式 + source 源码安装的方式安装 node-v18.12.1。\n\n所以,最终的方法为调整 ./scripts/common_startup.sh 中 nodeenv -n "$NODE_VERSION" -p 的安装代码如下:\nnodeenv -n "$NODE_VERSION" -p --source --ignore_ssl_certs --jobs=1\nnode-v18.12.1 下载地址:https://nodejs.org/download/release/v18.12.1/。\n由于编译非常耗时(4核8G 的服务器编译了 1 个小时左右),且对 Python 版本有要求,建议手动安装,具体安装步骤如下。\nshenweiyan@centos-vm-7 10:30:34 /home/shenweiyan/src/node-v18.12.1\n$ ./configure --prefix=/home/shenweiyan/software/node-v18.12.1\nNode.js configure: Found Python 3.11.6...\nPlease use python3.10 or python3.9 or python3.8 or python3.7 or python3.6.\n$ wget https://nodejs.org/download/release/v18.12.1/node-v18.12.1.tar.gz\n$ tar zvxf node-v18.12.1.tar.gz\n$ cd node-v18.12.1\n$ source /opt/rh/devtoolset-9/enable\n$ ./configure --prefix=/home/shenweiyan/software/node-v18.12.1\nNode.js configure: Found Python 3.9.18...\nINFO: configure completed successfully\n$ make -j 4\n$ make install\nYarn 环境\n注意要先设置 npm 的路径,如果有多个版本的 npm,会因为版本混乱导致语法异常。\nexport PATH=/home/shenweiyan/software/node-v18.12.1/bin:$PATH\n/home/shenweiyan/software/node-v18.12.1/bin/npm install --global yarn\npip 源\nGalaxy 在安装 requirements.txt 的时候默认使用下面两个源:\n\nhttps://wheels.galaxyproject.org/simple\nhttps://pypi.python.org/simple\n\n对于国内服务器,可以考虑更换为阿里云或者清华大学的 pip 源。可以:\n\n\n在 scripts/common_startup.sh 中修改:\n: ${PYPI_INDEX_URL:="https://mirrors.aliyun.com/pypi/simple/"}\n\n\n在 requirements.txt 头部增加:\n-i https://mirrors.aliyun.com/pypi/simple/\n--extra-index-url https://wheels.galaxyproject.org/simple\n\n\n数据库升级\n这是本次 Galaxy 核心版本升级时候遇到的最大问题。\n由于 Galaxy 在 release_21.05 新增加了一个 history_audit 数据表,release_20.09 的数据库直接执行 sh manage_db.sh upgrade 升级的时候 history_audit 数据表并不会一并创建和更新,因此最终导致在 Galaxy 服务启动的时候发生错误。\n这应该是数据库升级时候的一个bug,经过摸索发现,目前可以参考下面的文章,通过分步升级的方式解决。\n\nhttps://mp.weixin.qq.com/s/arRZ-3mMrpUIsXYuqg4sGQ\n\n以上解决方法,参考:galaxyproject/galaxy #19016\n\n总结\n更新后的 release_24.0 界面看起来比旧版本要更加清爽舒服一些,各个页面的汉化功能也有所改善,新增的 Notifications 功能也挺不错,总之升级之后各个方面还是挺满意的,其他细节和功能还在体验中。', 'bodyHTML': '

记录一下 Galaxy 分析平台从 release_20.09 升级到 release_24.0,横跨九个发布版本的升级之路。

\n\n

为什么要升级

\n

很主要的一个原因是随着新技术的更新,旧版本的使用可能会存在一些安全隐患,尤其对于提供互联网公开访问的平台。新版本的升级有助于捕获并应用所有先前的安全更新,以确保平台的安全性。

\n

版本选择

\n

最开始选择的是 release_24.1 版本,但好不容易安装完成后才发现,这个新版本中增加了一个常规途径下无法隐藏的 Activity Bar Interface,一时间无法忍受。
\n23.1-activity-bar
\ngalaxy-24.1

\n

第二个原因是,后台 PostgreSQL 数据库的升级遇到了 function gen_random_uuid() does not exist 异常,一下子没法解决也不想去升级 PostgreSQL 版本。

\n

所以,最终选择了从 release_20.09 升级到次新的 release_24.0 版本方案。

\n

安装系统环境

\n

这里以 release_24.1 作为示例,该环境要求同样适用于 release_24.0。

\n

Galaxy release_24.1 默认安装 node-v18.12.1,参考:run.sh./scripts/common_startup_functions.sh./scripts/common_startup.shnodeenv -n "$NODE_VERSION" -p 的安装代码。

\n

node-v18.12.1 下载地址:https://nodejs.org/download/release/v18.12.1/

\n

node-v18.12.1 要求 g++ 8.3.0 or clang++ 8.0.0:
\nnode-v18.12.1-gcc

\n

可以通过安装 Devtoolset 的方式解决:

\n
    \n
  1. 手动调整 CentOS 7 的 SCL YUM 源(也可以 yum 安装),注意变更 baseurl 为阿里云或者其他的源链接。\n
    # 会默认在 /etc/yum.repos.d 下生成 2 个 repo 源文件\n# CentOS-SCLo-scl.repo\n# CentOS-SCLo-scl-rh.repo\nyum install centos-release-scl centos-release-scl-rh
    \n
  2. \n
  3. 更新 yum 源的缓存。\n
    cd /etc/yum.repos.d\nyum clean all\nyum makecache
    \n
  4. \n
  5. 安装 scl-utils,scl-utils 是管理 SCL (Software Collection) 环境设置和运行软件的一套软件工具。\n
    yum install scl-utils
    \n
  6. \n
  7. 安装 devtoolset-9。\n
    yum install devtoolset-9
    \n
  8. \n
  9. 激活 devtoolset-9。\n
    source /opt/rh/devtoolset-9/enable
    \n
  10. \n
\n

Python 环境

\n

Galaxy 要求 Python >= 3.8,node-v18.12.1 要求 3.6<=Python<=3.10,这里选择 Python-3.9.18,安装如下。

\n
wget https://www.python.org/ftp/python/3.9.18/Python-3.9.18.tgz\ntar zvxf Python-3.9.18.tgz\ncd Python-3.9.18\n$enabledevtoolset9\nexport TCLTK_LIBS="-L/home/shenweiyan/software/tcltK-8.5.19/lib -ltcl8.5 -ltk8.5"\nexport TCLTK_CFLAGS="-I/home/shenweiyan/software/tcltK-8.5.19/include"\n./configure --enable-optimizations --prefix=/home/shenweiyan/software/python-3.9.18 --with-openssl=/home/shenweiyan/software/openssl-1.1.1/ --with-tcltk-includes="-I/home/shenweiyan/software/tcltK-8.5.19/include" --with-tcltk-libs="-L/home/shenweiyan/software/tcltK-8.5.19/lib -ltcl8.5 -ltk8.5" \nmake -j 4\nmake install
\n

Python-3.9.18 安装完成后,避免 ssl 模块无法正常 import 使用,需要在环境中增加以下设置。

\n
export LD_LIBRARY_PATH=/home/shenweiyan/software/openssl-1.1.1/lib:$LD_LIBRARY_PATH
\n

Node 环境

\n

Galaxy 的 sh run.sh 默认通过 ssl 的方式安装已经提前编译好的 node-v18.12.1-linux-x64.tar.gz(直接解压即可使用),对于系统版本比较低的服务器(如 CentOS 7)会存在 GLIBC 异常,因此需要调整为 ignore_ssl_certs 的下载方式 + source 源码安装的方式安装 node-v18.12.1。
\nnodeenv--help

\n

所以,最终的方法为调整 ./scripts/common_startup.shnodeenv -n "$NODE_VERSION" -p 的安装代码如下:

\n
nodeenv -n "$NODE_VERSION" -p --source --ignore_ssl_certs --jobs=1
\n

node-v18.12.1 下载地址:https://nodejs.org/download/release/v18.12.1/

\n

由于编译非常耗时(4核8G 的服务器编译了 1 个小时左右),且对 Python 版本有要求,建议手动安装,具体安装步骤如下。

\n
shenweiyan@centos-vm-7 10:30:34 /home/shenweiyan/src/node-v18.12.1\n$ ./configure --prefix=/home/shenweiyan/software/node-v18.12.1\nNode.js configure: Found Python 3.11.6...\nPlease use python3.10 or python3.9 or python3.8 or python3.7 or python3.6.
\n
$ wget https://nodejs.org/download/release/v18.12.1/node-v18.12.1.tar.gz\n$ tar zvxf node-v18.12.1.tar.gz\n$ cd node-v18.12.1\n$ source /opt/rh/devtoolset-9/enable\n$ ./configure --prefix=/home/shenweiyan/software/node-v18.12.1\nNode.js configure: Found Python 3.9.18...\nINFO: configure completed successfully\n$ make -j 4\n$ make install
\n

Yarn 环境

\n

注意要先设置 npm 的路径,如果有多个版本的 npm,会因为版本混乱导致语法异常。

\n
export PATH=/home/shenweiyan/software/node-v18.12.1/bin:$PATH\n/home/shenweiyan/software/node-v18.12.1/bin/npm install --global yarn
\n

pip 源

\n

Galaxy 在安装 requirements.txt 的时候默认使用下面两个源:

\n\n

对于国内服务器,可以考虑更换为阿里云或者清华大学的 pip 源。可以:

\n
    \n
  • \n

    scripts/common_startup.sh 中修改:

    \n
    : ${PYPI_INDEX_URL:="https://mirrors.aliyun.com/pypi/simple/"}
    \n
  • \n
  • \n

    requirements.txt 头部增加:

    \n
    -i https://mirrors.aliyun.com/pypi/simple/\n--extra-index-url https://wheels.galaxyproject.org/simple
    \n
  • \n
\n

数据库升级

\n

这是本次 Galaxy 核心版本升级时候遇到的最大问题。

\n

由于 Galaxy 在 release_21.05 新增加了一个 history_audit 数据表,release_20.09 的数据库直接执行 sh manage_db.sh upgrade 升级的时候 history_audit 数据表并不会一并创建和更新,因此最终导致在 Galaxy 服务启动的时候发生错误。

\n

这应该是数据库升级时候的一个bug,经过摸索发现,目前可以参考下面的文章,通过分步升级的方式解决。

\n\n

以上解决方法,参考:galaxyproject/galaxy #19016

\n

galaxy-issues-19016

\n

总结

\n

更新后的 release_24.0 界面看起来比旧版本要更加清爽舒服一些,各个页面的汉化功能也有所改善,新增的 Notifications 功能也挺不错,总之升级之后各个方面还是挺满意的,其他细节和功能还在体验中。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '3.1-Galaxy'}, 'labels': {'nodes': [{'name': '3.1.x-GalaxyOther'}]}, 'comments': {'nodes': []}}, {'title': '上下班听广播', 'number': 89, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/89', 'createdAt': '2024-09-29T06:11:30Z', 'lastEditedAt': '2024-09-29T06:33:13Z', 'updatedAt': '2024-09-29T07:09:40Z', 'body': '自从切换了电动车的通勤方式,同时就打开了广播的大门。\r\n\r\n\r\n\r\n![hello-morning](https://kg.weiyan.cc/2024/09/hello-morning.webp)\r\n\r\n符合自己兴趣的电台不好找,尤其是下午下班的这段时间。\r\n\r\n## 珠江第一线\r\n\r\n珠江第一线,朝朝陪你饮早茶!\r\n\r\n早上的选择中个人尤其喜欢珠江经济台的《珠江第一线》,它的播出时间是周一到周五的 07:30-09:00,是珠江经济台重点打造的一档粤语民生新闻名牌节目,李嘉、淼钧、郑达等一众名嘴的组合,加上独具的广府文化韵味,针砭时弊,作风硬朗,嬉笑怒骂,亦庄亦谐,让人在上班的路上更加放松。\r\n\r\n> 《珠江第一线》开播之时,就在广东广播界率先提出“打造听众上班路上的新闻资讯大餐”的口号。节目立足民生视觉,着重在内容碎片化上下功夫,让海量资讯更有层次感,更适合伴随性收听的人群;另外增加生活化话题、软性资讯,讲老百姓身边的故事,塑造老百姓“贴心老友”节目品牌形象;同时强化新闻时评的针对性,聘请最强广播评论专家团队,与市民评论员联袂,每天对社会热点话题进行精辟点评;节目主持人也一改传统的新闻节目播报方式,使用个性化的“说新闻”,节目过程还不时插播上班路上的交通、天气状况,使节目更接地气,更具亲和力。\r\n\r\n## 放工路上\r\n\r\n下班时间段的选择,要说十分喜欢的节目目前没找到,虽然会听同样是珠江经济台的《珠江晚高峰》,但找不到《珠江第一线》的舒适感。\r\n', 'bodyText': '自从切换了电动车的通勤方式,同时就打开了广播的大门。\n\n\n符合自己兴趣的电台不好找,尤其是下午下班的这段时间。\n珠江第一线\n珠江第一线,朝朝陪你饮早茶!\n早上的选择中个人尤其喜欢珠江经济台的《珠江第一线》,它的播出时间是周一到周五的 07:30-09:00,是珠江经济台重点打造的一档粤语民生新闻名牌节目,李嘉、淼钧、郑达等一众名嘴的组合,加上独具的广府文化韵味,针砭时弊,作风硬朗,嬉笑怒骂,亦庄亦谐,让人在上班的路上更加放松。\n\n《珠江第一线》开播之时,就在广东广播界率先提出“打造听众上班路上的新闻资讯大餐”的口号。节目立足民生视觉,着重在内容碎片化上下功夫,让海量资讯更有层次感,更适合伴随性收听的人群;另外增加生活化话题、软性资讯,讲老百姓身边的故事,塑造老百姓“贴心老友”节目品牌形象;同时强化新闻时评的针对性,聘请最强广播评论专家团队,与市民评论员联袂,每天对社会热点话题进行精辟点评;节目主持人也一改传统的新闻节目播报方式,使用个性化的“说新闻”,节目过程还不时插播上班路上的交通、天气状况,使节目更接地气,更具亲和力。\n\n放工路上\n下班时间段的选择,要说十分喜欢的节目目前没找到,虽然会听同样是珠江经济台的《珠江晚高峰》,但找不到《珠江第一线》的舒适感。', 'bodyHTML': '

自从切换了电动车的通勤方式,同时就打开了广播的大门。

\n\n

hello-morning

\n

符合自己兴趣的电台不好找,尤其是下午下班的这段时间。

\n

珠江第一线

\n

珠江第一线,朝朝陪你饮早茶!

\n

早上的选择中个人尤其喜欢珠江经济台的《珠江第一线》,它的播出时间是周一到周五的 07:30-09:00,是珠江经济台重点打造的一档粤语民生新闻名牌节目,李嘉、淼钧、郑达等一众名嘴的组合,加上独具的广府文化韵味,针砭时弊,作风硬朗,嬉笑怒骂,亦庄亦谐,让人在上班的路上更加放松。

\n
\n

《珠江第一线》开播之时,就在广东广播界率先提出“打造听众上班路上的新闻资讯大餐”的口号。节目立足民生视觉,着重在内容碎片化上下功夫,让海量资讯更有层次感,更适合伴随性收听的人群;另外增加生活化话题、软性资讯,讲老百姓身边的故事,塑造老百姓“贴心老友”节目品牌形象;同时强化新闻时评的针对性,聘请最强广播评论专家团队,与市民评论员联袂,每天对社会热点话题进行精辟点评;节目主持人也一改传统的新闻节目播报方式,使用个性化的“说新闻”,节目过程还不时插播上班路上的交通、天气状况,使节目更接地气,更具亲和力。

\n
\n

放工路上

\n

下班时间段的选择,要说十分喜欢的节目目前没找到,虽然会听同样是珠江经济台的《珠江晚高峰》,但找不到《珠江第一线》的舒适感。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'All in one', 'number': 88, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/88', 'createdAt': '2024-09-24T07:36:36Z', 'lastEditedAt': None, 'updatedAt': '2024-09-24T07:36:37Z', 'body': '写笔记,做表格的很多时候,总有一个 All in one 的魔咒在脑海挥之不去,以前用语雀就想当然 All in yuque,后来又想着 All in GitHub,但现实终究是现实。\r\n\r\n\r\n\r\n没有十全十美的平台,语雀就没有邮箱、日历之类的功能;小记也没有浮墨笔记那么好用。\r\n\r\nGitHub 虽好,但始终有一堵长城横亘在前面,时时刻刻提醒着你小心翼翼。\r\n\r\n现在的飞书,各种功能都很齐全,但是不能实时查看文档的 Markdown,自己也没有能力去造这样一个轮子。有很多的时候,都有一个 All in feishu 的魔咒的诱惑着我,但又一次一次被它的木桶理论劝退。\r\n\r\n知识的沉淀,对于承受的载体没有什么是可以从一而终一成不变的,很多东西虽然分散,但也印证了不要把所有的鸡蛋放进一个篮子。逐渐的,我用上了飞书国际版的邮箱,我用上了语雀(小记/知识库)来记录我的一些碎片想法和文字,最终还是选择 GitHub 来记录这一切。\r\n\r\n不得不说,GitHub 真是个码字的好地方。', 'bodyText': '写笔记,做表格的很多时候,总有一个 All in one 的魔咒在脑海挥之不去,以前用语雀就想当然 All in yuque,后来又想着 All in GitHub,但现实终究是现实。\n\n没有十全十美的平台,语雀就没有邮箱、日历之类的功能;小记也没有浮墨笔记那么好用。\nGitHub 虽好,但始终有一堵长城横亘在前面,时时刻刻提醒着你小心翼翼。\n现在的飞书,各种功能都很齐全,但是不能实时查看文档的 Markdown,自己也没有能力去造这样一个轮子。有很多的时候,都有一个 All in feishu 的魔咒的诱惑着我,但又一次一次被它的木桶理论劝退。\n知识的沉淀,对于承受的载体没有什么是可以从一而终一成不变的,很多东西虽然分散,但也印证了不要把所有的鸡蛋放进一个篮子。逐渐的,我用上了飞书国际版的邮箱,我用上了语雀(小记/知识库)来记录我的一些碎片想法和文字,最终还是选择 GitHub 来记录这一切。\n不得不说,GitHub 真是个码字的好地方。', 'bodyHTML': '

写笔记,做表格的很多时候,总有一个 All in one 的魔咒在脑海挥之不去,以前用语雀就想当然 All in yuque,后来又想着 All in GitHub,但现实终究是现实。

\n\n

没有十全十美的平台,语雀就没有邮箱、日历之类的功能;小记也没有浮墨笔记那么好用。

\n

GitHub 虽好,但始终有一堵长城横亘在前面,时时刻刻提醒着你小心翼翼。

\n

现在的飞书,各种功能都很齐全,但是不能实时查看文档的 Markdown,自己也没有能力去造这样一个轮子。有很多的时候,都有一个 All in feishu 的魔咒的诱惑着我,但又一次一次被它的木桶理论劝退。

\n

知识的沉淀,对于承受的载体没有什么是可以从一而终一成不变的,很多东西虽然分散,但也印证了不要把所有的鸡蛋放进一个篮子。逐渐的,我用上了飞书国际版的邮箱,我用上了语雀(小记/知识库)来记录我的一些碎片想法和文字,最终还是选择 GitHub 来记录这一切。

\n

不得不说,GitHub 真是个码字的好地方。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'GCC 版本不一致导致的 R magick 包安装错误', 'number': 87, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/87', 'createdAt': '2024-09-10T05:43:01Z', 'lastEditedAt': '2024-09-11T03:00:33Z', 'updatedAt': '2024-09-11T03:00:33Z', 'body': '在安装 Y 叔的 `yyplot` 时候,发现 `magick` 依赖包安装的时候的一些棘手问题,特此记录一下。\r\n\r\n\r\n\r\n## R-4.0.3 安装\r\n\r\n```r\r\n> library(remotes)\r\n> remotes::install_github("GuangchuangYu/yyplot")\r\n...\r\n* installing *source* package ‘magick’ ...\r\n** package ‘magick’ successfully unpacked and MD5 sums checked\r\n** using staged installation\r\nPackage Magick++ was not found in the pkg-config search path.\r\nPerhaps you should add the directory containing `Magick++.pc\'\r\nto the PKG_CONFIG_PATH environment variable\r\nNo package \'Magick++\' found\r\nUsing PKG_CFLAGS=\r\nUsing PKG_LIBS=-lMagick++-6.Q16 -lMagickWand-6.Q16 -lMagickCore-6.Q16\r\n--------------------------- [ANTICONF] --------------------------------\r\nConfiguration failed to find the Magick++ library. Try installing:\r\n - deb: libmagick++-dev (Debian, Ubuntu)\r\n - rpm: ImageMagick-c++-devel (Fedora, CentOS, RHEL)\r\n - brew: imagemagick or imagemagick@6 (MacOS)\r\nIf Magick++ is already installed, check that \'pkg-config\' is in your\r\nPATH and PKG_CONFIG_PATH contains a Magick++.pc file. If pkg-config\r\nis unavailable you can set INCLUDE_DIR and LIB_DIR manually via:\r\nR CMD INSTALL --configure-vars=\'INCLUDE_DIR=... LIB_DIR=...\'\r\n-------------------------- [ERROR MESSAGE] ---------------------------\r\n:1:22: fatal error: Magick++.h: No such file or directory\r\ncompilation terminated.\r\n--------------------------------------------------------------------\r\nERROR: configuration failed for package ‘magick’\r\n* removing ‘/home/shenweiyan/software/R/R-4.0.3/lib64/R/library/magick’\r\nError: Failed to install \'yyplot\' from GitHub:\r\n (converted from warning) installation of package ‘magick’ had non-zero exit status\r\n> quit()\r\nSave workspace image? [y/n/c]: n\r\n```\r\n\r\n仅在 Bash 环境配置了 `PATH` 和 `PKG_CONFIG_PATH` 是不够的,安装过程会提示动态库的问题。 \r\n```\r\n# export PATH=/home/shenweiyan/software/ImageMagick-7.0.10/bin:$PATH\r\n# export PKG_CONFIG_PATH=/home/shenweiyan/software/ImageMagick-7.0.10/lib/pkgconfig:$PKG_CONFIG_PATH\r\n```\r\n\r\n```r\r\n> library(remotes)\r\n> remotes::install_github("GuangchuangYu/yyplot")\r\n...\r\n** R\r\n** inst\r\n** byte-compile and prepare package for lazy loading\r\n** help\r\n*** installing help indices\r\n** building package indices\r\n** installing vignettes\r\n** testing if installed package can be loaded from temporary location\r\nError: package or namespace load failed for ‘magick’ in dyn.load(file, DLLpath = DLLpath, ...):\r\n unable to load shared object \'/home/shenweiyan/software/R/R-4.0.3/lib64/R/library/00LOCK-magick/00new/magick/libs/magick.so\':\r\n libMagick++-7.Q16HDRI.so.4: cannot open shared object file: No such file or directory\r\nError: loading failed\r\nExecution halted\r\nERROR: loading failed\r\n* removing ‘/home/shenweiyan/software/R/R-4.0.3/lib64/R/library/magick’\r\nError: Failed to install \'yyplot\' from GitHub:\r\n (converted from warning) installation of package ‘magick’ had non-zero exit status\r\n> quit()\r\nSave workspace image? [y/n/c]: n\r\n```\r\n最终解决方案:\r\n\r\n1. 手动安装 `ggimage_0.3.1`。\r\n```r\r\npkg <- \'http://cran.r-project.org/src/contrib/Archive/ggimage/ggimage_0.3.1.tar.gz\'\r\ninstall.packages(pkg, repos=NULL, type="source")\r\n```\r\n\r\n2. 配置必要环境。\r\n```bash\r\nexport PATH=/home/shenweiyan/software/ImageMagick-7.0.10/bin:$PATH\r\nexport PKG_CONFIG_PATH=/home/shenweiyan/software/ImageMagick-7.0.10/lib/pkgconfig:$PKG_CONFIG_PATH\r\nexport LD_LIBRARY_PATH=/home/shenweiyan/software/ImageMagick-7.0.10/lib:$LD_LIBRARY_PATH\r\n```\r\n\r\n3. 安装。根据提示,先安装缺失的 `meme` 包,然后再安装 `yyplot`。\r\n```r\r\n> library(remotes)\r\n> options("repos"=c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))\r\n> install.packages(\'meme\')\r\n> remotes::install_github("GuangchuangYu/yyplot")\r\n```\r\n\r\n## R-4.3.0 安装\r\n\r\nR-4.3.0 安装 `magick_2.8.4` 会出现 [ropensci/magick#166](https://github.com/ropensci/magick/issues/166) 的问题。根据 [ropensci/magick#166#issuecomment-457875591](https://github.com/ropensci/magick/issues/166#issuecomment-457875591) 的描述,**编译 ImageMagick 的 gcc 需要跟编译 R 的 gcc 保持版本一致**。\r\n\r\n1. 重新编译安装 ImageMagick\r\n```bash\r\nwget https://download.imagemagick.org/archive/releases/ImageMagick-7.0.10-24.tar.xz\r\nextract ImageMagick-7.0.10-24.tar.xz\r\ncd ImageMagick-7.0.10-24\r\n./configure CC=/home/shenweiyan/software/gcc-7.3.0/bin/gcc CXX=/home/shenweiyan/software/gcc-7.3.0/bin/g++ --prefix=/home/shenweiyan/software/ImageMagick-7.0.10-24\r\nmake \r\nmake install\r\n```\r\n\r\n2. 安装 `magick` 包\r\n```bash\r\n# export PATH=/home/shenweiyan/software/ImageMagick-7.0.10-24/bin:$PATH\r\n# export PKG_CONFIG_PATH=/home/shenweiyan/software/ImageMagick-7.0.10-24/lib/pkgconfig:$PKG_CONFIG_PATH\r\n# export LD_LIBRARY_PATH=/home/shenweiyan/software/ImageMagick-7.0.10-24/lib:$LD_LIBRARY_PATH\r\n/home/shenweiyan/software/R/R-4.3.0/bin/R\r\n> options("repos"=c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))\r\n> install.packages(\'magick\')\r\n...\r\n```\r\n\r\n3. 根据提示,先安装缺失的 `meme` 包,然后再安装 `yyplot`。\r\n```r\r\n> library(remotes)\r\n> options("repos"=c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))\r\n> install.packages(\'meme\')\r\n> remotes::install_github("GuangchuangYu/yyplot")\r\n```', 'bodyText': '在安装 Y 叔的 yyplot 时候,发现 magick 依赖包安装的时候的一些棘手问题,特此记录一下。\n\nR-4.0.3 安装\n> library(remotes)\n> remotes::install_github("GuangchuangYu/yyplot")\n...\n* installing *source* package ‘magick’ ...\n** package ‘magick’ successfully unpacked and MD5 sums checked\n** using staged installation\nPackage Magick++ was not found in the pkg-config search path.\nPerhaps you should add the directory containing `Magick++.pc\'\nto the PKG_CONFIG_PATH environment variable\nNo package \'Magick++\' found\nUsing PKG_CFLAGS=\nUsing PKG_LIBS=-lMagick++-6.Q16 -lMagickWand-6.Q16 -lMagickCore-6.Q16\n--------------------------- [ANTICONF] --------------------------------\nConfiguration failed to find the Magick++ library. Try installing:\n - deb: libmagick++-dev (Debian, Ubuntu)\n - rpm: ImageMagick-c++-devel (Fedora, CentOS, RHEL)\n - brew: imagemagick or imagemagick@6 (MacOS)\nIf Magick++ is already installed, check that \'pkg-config\' is in your\nPATH and PKG_CONFIG_PATH contains a Magick++.pc file. If pkg-config\nis unavailable you can set INCLUDE_DIR and LIB_DIR manually via:\nR CMD INSTALL --configure-vars=\'INCLUDE_DIR=... LIB_DIR=...\'\n-------------------------- [ERROR MESSAGE] ---------------------------\n:1:22: fatal error: Magick++.h: No such file or directory\ncompilation terminated.\n--------------------------------------------------------------------\nERROR: configuration failed for package ‘magick’\n* removing ‘/home/shenweiyan/software/R/R-4.0.3/lib64/R/library/magick’\nError: Failed to install \'yyplot\' from GitHub:\n (converted from warning) installation of package ‘magick’ had non-zero exit status\n> quit()\nSave workspace image? [y/n/c]: n\n仅在 Bash 环境配置了 PATH 和 PKG_CONFIG_PATH 是不够的,安装过程会提示动态库的问题。\n# export PATH=/home/shenweiyan/software/ImageMagick-7.0.10/bin:$PATH\n# export PKG_CONFIG_PATH=/home/shenweiyan/software/ImageMagick-7.0.10/lib/pkgconfig:$PKG_CONFIG_PATH\n\n> library(remotes)\n> remotes::install_github("GuangchuangYu/yyplot")\n...\n** R\n** inst\n** byte-compile and prepare package for lazy loading\n** help\n*** installing help indices\n** building package indices\n** installing vignettes\n** testing if installed package can be loaded from temporary location\nError: package or namespace load failed for ‘magick’ in dyn.load(file, DLLpath = DLLpath, ...):\n unable to load shared object \'/home/shenweiyan/software/R/R-4.0.3/lib64/R/library/00LOCK-magick/00new/magick/libs/magick.so\':\n libMagick++-7.Q16HDRI.so.4: cannot open shared object file: No such file or directory\nError: loading failed\nExecution halted\nERROR: loading failed\n* removing ‘/home/shenweiyan/software/R/R-4.0.3/lib64/R/library/magick’\nError: Failed to install \'yyplot\' from GitHub:\n (converted from warning) installation of package ‘magick’ had non-zero exit status\n> quit()\nSave workspace image? [y/n/c]: n\n最终解决方案:\n\n手动安装 ggimage_0.3.1。\n\npkg <- \'http://cran.r-project.org/src/contrib/Archive/ggimage/ggimage_0.3.1.tar.gz\'\ninstall.packages(pkg, repos=NULL, type="source")\n\n配置必要环境。\n\nexport PATH=/home/shenweiyan/software/ImageMagick-7.0.10/bin:$PATH\nexport PKG_CONFIG_PATH=/home/shenweiyan/software/ImageMagick-7.0.10/lib/pkgconfig:$PKG_CONFIG_PATH\nexport LD_LIBRARY_PATH=/home/shenweiyan/software/ImageMagick-7.0.10/lib:$LD_LIBRARY_PATH\n\n安装。根据提示,先安装缺失的 meme 包,然后再安装 yyplot。\n\n> library(remotes)\n> options("repos"=c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))\n> install.packages(\'meme\')\n> remotes::install_github("GuangchuangYu/yyplot")\nR-4.3.0 安装\nR-4.3.0 安装 magick_2.8.4 会出现 ropensci/magick#166 的问题。根据 ropensci/magick#166#issuecomment-457875591 的描述,编译 ImageMagick 的 gcc 需要跟编译 R 的 gcc 保持版本一致。\n\n重新编译安装 ImageMagick\n\nwget https://download.imagemagick.org/archive/releases/ImageMagick-7.0.10-24.tar.xz\nextract ImageMagick-7.0.10-24.tar.xz\ncd ImageMagick-7.0.10-24\n./configure CC=/home/shenweiyan/software/gcc-7.3.0/bin/gcc CXX=/home/shenweiyan/software/gcc-7.3.0/bin/g++ --prefix=/home/shenweiyan/software/ImageMagick-7.0.10-24\nmake \nmake install\n\n安装 magick 包\n\n# export PATH=/home/shenweiyan/software/ImageMagick-7.0.10-24/bin:$PATH\n# export PKG_CONFIG_PATH=/home/shenweiyan/software/ImageMagick-7.0.10-24/lib/pkgconfig:$PKG_CONFIG_PATH\n# export LD_LIBRARY_PATH=/home/shenweiyan/software/ImageMagick-7.0.10-24/lib:$LD_LIBRARY_PATH\n/home/shenweiyan/software/R/R-4.3.0/bin/R\n> options("repos"=c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))\n> install.packages(\'magick\')\n...\n\n根据提示,先安装缺失的 meme 包,然后再安装 yyplot。\n\n> library(remotes)\n> options("repos"=c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))\n> install.packages(\'meme\')\n> remotes::install_github("GuangchuangYu/yyplot")', 'bodyHTML': '

在安装 Y 叔的 yyplot 时候,发现 magick 依赖包安装的时候的一些棘手问题,特此记录一下。

\n\n

R-4.0.3 安装

\n
> library(remotes)\n> remotes::install_github("GuangchuangYu/yyplot")\n...\n* installing *source* packagemagick...\n** packagemagicksuccessfully unpacked and MD5 sums checked\n** using staged installation\nPackage Magick++ was not found in the pkg-config search path.\nPerhaps you should add the directory containing `Magick++.pc\'\nto the PKG_CONFIG_PATH environment variable\nNo package \'Magick++\' found\nUsing PKG_CFLAGS=\nUsing PKG_LIBS=-lMagick++-6.Q16 -lMagickWand-6.Q16 -lMagickCore-6.Q16\n--------------------------- [ANTICONF] --------------------------------\nConfiguration failed to find the Magick++ library. Try installing:\n - deb: libmagick++-dev (Debian, Ubuntu)\n - rpm: ImageMagick-c++-devel (Fedora, CentOS, RHEL)\n - brew: imagemagick or imagemagick@6 (MacOS)\nIf Magick++ is already installed, check that \'pkg-config\' is in your\nPATH and PKG_CONFIG_PATH contains a Magick++.pc file. If pkg-config\nis unavailable you can set INCLUDE_DIR and LIB_DIR manually via:\nR CMD INSTALL --configure-vars=\'INCLUDE_DIR=... LIB_DIR=...\'\n-------------------------- [ERROR MESSAGE] ---------------------------\n<stdin>:1:22: fatal error: Magick++.h: No such file or directory\ncompilation terminated.\n--------------------------------------------------------------------\nERROR: configuration failed for package ‘magick’\n* removing ‘/home/shenweiyan/software/R/R-4.0.3/lib64/R/library/magick’\nError: Failed to install \'yyplot\' from GitHub:\n  (converted from warning) installation of package ‘magick’ had non-zero exit status\n> quit()\nSave workspace image? [y/n/c]: n
\n

仅在 Bash 环境配置了 PATHPKG_CONFIG_PATH 是不够的,安装过程会提示动态库的问题。

\n
# export PATH=/home/shenweiyan/software/ImageMagick-7.0.10/bin:$PATH\n# export PKG_CONFIG_PATH=/home/shenweiyan/software/ImageMagick-7.0.10/lib/pkgconfig:$PKG_CONFIG_PATH\n
\n
> library(remotes)\n> remotes::install_github("GuangchuangYu/yyplot")\n...\n** R\n** inst\n** byte-compile and prepare package for lazy loading\n** help\n*** installing help indices\n** building package indices\n** installing vignettes\n** testing if installed package can be loaded from temporary location\nError: package or namespace load failed formagickin dyn.load(file, DLLpath = DLLpath, ...):\n unable to load shared object \'/home/shenweiyan/software/R/R-4.0.3/lib64/R/library/00LOCK-magick/00new/magick/libs/magick.so\':\n  libMagick++-7.Q16HDRI.so.4: cannot open shared object file: No such file or directory\nError: loading failed\nExecution halted\nERROR: loading failed\n* removing/home/shenweiyan/software/R/R-4.0.3/lib64/R/library/magick’\nError: Failed to install \'yyplot\' from GitHub:\n  (converted from warning) installation of packagemagickhad non-zero exit status\n> quit()\nSave workspace image? [y/n/c]: n
\n

最终解决方案:

\n
    \n
  1. 手动安装 ggimage_0.3.1
  2. \n
\n
pkg <- \'http://cran.r-project.org/src/contrib/Archive/ggimage/ggimage_0.3.1.tar.gz\'\ninstall.packages(pkg, repos=NULL, type="source")
\n
    \n
  1. 配置必要环境。
  2. \n
\n
export PATH=/home/shenweiyan/software/ImageMagick-7.0.10/bin:$PATH\nexport PKG_CONFIG_PATH=/home/shenweiyan/software/ImageMagick-7.0.10/lib/pkgconfig:$PKG_CONFIG_PATH\nexport LD_LIBRARY_PATH=/home/shenweiyan/software/ImageMagick-7.0.10/lib:$LD_LIBRARY_PATH
\n
    \n
  1. 安装。根据提示,先安装缺失的 meme 包,然后再安装 yyplot
  2. \n
\n
> library(remotes)\n> options("repos"=c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))\n> install.packages(\'meme\')\n> remotes::install_github("GuangchuangYu/yyplot")
\n

R-4.3.0 安装

\n

R-4.3.0 安装 magick_2.8.4 会出现 ropensci/magick#166 的问题。根据 ropensci/magick#166#issuecomment-457875591 的描述,编译 ImageMagick 的 gcc 需要跟编译 R 的 gcc 保持版本一致

\n
    \n
  1. 重新编译安装 ImageMagick
  2. \n
\n
wget https://download.imagemagick.org/archive/releases/ImageMagick-7.0.10-24.tar.xz\nextract ImageMagick-7.0.10-24.tar.xz\ncd ImageMagick-7.0.10-24\n./configure CC=/home/shenweiyan/software/gcc-7.3.0/bin/gcc CXX=/home/shenweiyan/software/gcc-7.3.0/bin/g++ --prefix=/home/shenweiyan/software/ImageMagick-7.0.10-24\nmake \nmake install
\n
    \n
  1. 安装 magick
  2. \n
\n
# export PATH=/home/shenweiyan/software/ImageMagick-7.0.10-24/bin:$PATH\n# export PKG_CONFIG_PATH=/home/shenweiyan/software/ImageMagick-7.0.10-24/lib/pkgconfig:$PKG_CONFIG_PATH\n# export LD_LIBRARY_PATH=/home/shenweiyan/software/ImageMagick-7.0.10-24/lib:$LD_LIBRARY_PATH\n/home/shenweiyan/software/R/R-4.3.0/bin/R\n> options("repos"=c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))\n> install.packages(\'magick\')\n...
\n
    \n
  1. 根据提示,先安装缺失的 meme 包,然后再安装 yyplot
  2. \n
\n
> library(remotes)\n> options("repos"=c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))\n> install.packages(\'meme\')\n> remotes::install_github("GuangchuangYu/yyplot")
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '1.3.6-R'}]}, 'comments': {'nodes': []}}, {'title': 'Linux 下 PostgreSQL 源码编译安装', 'number': 86, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/86', 'createdAt': '2024-09-03T02:03:58Z', 'lastEditedAt': '2024-09-04T01:00:39Z', 'updatedAt': '2024-09-04T01:00:39Z', 'body': 'PostgreSQL 是一个功能强大的开源对象关系数据库管理系统(ORDBMS),它从伯克利写的 POSTGRES 软件包发展而来(1995 年几个 UCB 的学生为 Post-Ingres 开发了 SQL 的接口,正式发布了 PostgreSQL95,随后一步步在开源社区中成长起来),经过十几年的发展, PostgreSQL 已经成为世界上发展最快最受欢迎的数据库系统之一。\r\n\r\n本文章主要介绍在 CentOS 下源码编码安装 PostgreSQL-10.0 的一些简单步骤,以供参考。\r\n\r\n\r\n\r\n## 1. 新增用户组及用户\r\n\r\nPostgreSQL 默认是通过 `postgres:postgres` 来启动和使用的,因此在安装 PostgreSQL 前需要先创建 `postgres` 用户组及 `postgres` 用户。\r\n\r\n```bash\r\n# 在root权限下进行\r\ngroupadd postgres # 添加postgres用户组\r\nuseradd postgres -g postgres # 添加postgres用户\r\npasswd postgres # 设置postgres用户密码\r\n```\r\n\r\n## 2. 安装\r\n\r\n```\r\n$ wget https://ftp.postgresql.org/pub/source/v10.0/postgresql-10.0.tar.gz\r\n$ tar zvxf postgresql-10.0.tar.gz\r\n$ cd postgresql-10.0\r\n$ ./configure --prefix=/data/softwares/pgsql\r\n$ make\r\n$ make install\r\n```\r\n\r\n解决依赖:\r\n\r\n```\r\nFAQ1:configure: error: readline library not found\r\n$ yum install readline-devel\r\n\r\nFAQ2:configure: error: zlib library not found\r\n$ yum install zlib-devel\r\n```\r\n\r\n## 3. 启动\r\n\r\n```\r\n# 新建数据库数据文件目录\r\n$ mkdir /data/softwares/pgsql/data\r\n \r\n# 新建数据库 log 文件目录\r\n$ mkdir /data/softwares/pgsql/log\r\n \r\n# 修改目录拥有者\r\n$ chown postgres:postgres /data/softwares/pgsql/data -R\r\n$ chown postgres:postgres /data/softwares/pgsql/log -R\r\n \r\n# 执行数据库初始化脚本\r\n$ su postgres\r\n$ /data/softwares/pgsql/bin/initdb --encoding=utf8 -D /data/softwares/pgsql/data\r\n \r\n# 启动 PostgreSQL 服务\r\n$ /data/softwares/pgsql/bin/pg_ctl -D /data/softwares/pgsql/data -l /data/softwares/pgsql/log/postgresql.log start #postgres 用户下执行\r\n \r\n# 登录 PostgreSQL 数据库\r\n$ psql\r\n```\r\n\r\n![psql-db-list](https://kg.weiyan.cc/2024/09/psql-db-list.webp)\r\n\r\n## 4. 重启\r\n\r\n```\r\n$ su postgres\r\n$ /data/softwares/pgsql/bin/pg_ctl -D /data/softwares/pgsql/data -l /data/softwares/pgsql/log/postgresql.log restart\r\n```\r\n\r\n## 5. 设置开机启动\r\n\r\n解压后的 postgresql-x.x.x 下提供了基于 freebsd、linux、osx 3 个系统的 `postgresql` 启动命令。\r\n\r\n**1)对于通过源码自定义安装的 pgsql,需要修改相关启动脚本:**\r\n\r\n```bash\r\n$ cd postgresql-10.0/postgresql-10.0/contrib/start-scripts\r\n$ vi linux\r\n......\r\n......\r\n# Installation prefix\r\nprefix=/data/softwares/pgsql\r\n \r\n# Data directory\r\nPGDATA="/data/softwares/pgsql/data"\r\n \r\n# Who to run the postmaster as, usually "postgres". (NOT "root")\r\nPGUSER=postgres\r\n \r\n# Where to keep a log file\r\nPGLOG="$PGDATA/serverlog"\r\n......\r\n......\r\n```\r\n\r\n**2)设置数据库开机启动:**\r\n\r\n```bash\r\n$ cp /data/softwares/source/postgresql-10.0/postgresql-10.0/contrib/start-scripts/linux /etc/init.d/postgresql\r\n\r\n# 添加执行权限\r\n$ chmod a+x /etc/init.d/postgresql\r\n\r\n# 添加至开机启动\r\n$ chkconfig --add postgresql\r\n$ chkconfig postgresql on\r\n```\r\n\r\n**3)查看 postgresql 状态**\r\n\r\n```bash\r\n$ service postgresql status\r\npg_ctl: server is running (PID: 32586)\r\n/data/softwares/pgsql/bin/postgres "-D" "/data/softwares/pgsql/data"\r\n```\r\n\r\n## 6. 禁止管理员空密码登录\r\n\r\n在 PostgreSQL 中,如果你想禁止管理员(通常是 `postgres` 用户)使用空密码登录(正常情况下 `postgres` 用户可以直接使用 `psql` 命令直接登录 PostgreSQL),你可以通过修改 `pg_hba.conf` 文件来实现。\r\n\r\n1. 找到你的 `pg_hba.conf` 文件。这个文件通常位于 PostgreSQL 的数据目录中,例如 `/var/lib/pgsql/data` 或 `/etc/postgresql//main`。\r\n\r\n2. 修改 `pg_hba.conf` 文件,将管理员的登录方式从 `trust` 更改为 `md5` 或 `password`。这意味着所有连接,包括 `postgres` 用户的,都需要提供密码。\r\n\r\n例如,将以下行:\r\n```\r\nlocal all postgres trust\r\n```\r\n\r\n修改为:\r\n```\r\nlocal all postgres md5\r\n```\r\n\r\n3. 重新加载或重启 PostgreSQL 服务以应用更改。\r\n\r\n重新加载配置的命令通常是:\r\n```bash\r\npg_ctl reload\r\n```\r\n\r\n或者重启服务:\r\n```bash\r\nsystemctl restart postgresql\r\n```\r\n\r\n或者在不同的系统中可能是:\r\n```bash\r\nservice postgresql restart\r\n```\r\n\r\n完成这些步骤后,`postgres` 用户将不能再使用空密码登录数据库。其他用户如果想登录数据库,也需要提供密码。\r\n', 'bodyText': 'PostgreSQL 是一个功能强大的开源对象关系数据库管理系统(ORDBMS),它从伯克利写的 POSTGRES 软件包发展而来(1995 年几个 UCB 的学生为 Post-Ingres 开发了 SQL 的接口,正式发布了 PostgreSQL95,随后一步步在开源社区中成长起来),经过十几年的发展, PostgreSQL 已经成为世界上发展最快最受欢迎的数据库系统之一。\n本文章主要介绍在 CentOS 下源码编码安装 PostgreSQL-10.0 的一些简单步骤,以供参考。\n\n1. 新增用户组及用户\nPostgreSQL 默认是通过 postgres:postgres 来启动和使用的,因此在安装 PostgreSQL 前需要先创建 postgres 用户组及 postgres 用户。\n# 在root权限下进行\ngroupadd postgres # 添加postgres用户组\nuseradd postgres -g postgres # 添加postgres用户\npasswd postgres # 设置postgres用户密码\n2. 安装\n$ wget https://ftp.postgresql.org/pub/source/v10.0/postgresql-10.0.tar.gz\n$ tar zvxf postgresql-10.0.tar.gz\n$ cd postgresql-10.0\n$ ./configure --prefix=/data/softwares/pgsql\n$ make\n$ make install\n\n解决依赖:\nFAQ1:configure: error: readline library not found\n$ yum install readline-devel\n\nFAQ2:configure: error: zlib library not found\n$ yum install zlib-devel\n\n3. 启动\n# 新建数据库数据文件目录\n$ mkdir /data/softwares/pgsql/data\n \n# 新建数据库 log 文件目录\n$ mkdir /data/softwares/pgsql/log\n \n# 修改目录拥有者\n$ chown postgres:postgres /data/softwares/pgsql/data -R\n$ chown postgres:postgres /data/softwares/pgsql/log -R\n \n# 执行数据库初始化脚本\n$ su postgres\n$ /data/softwares/pgsql/bin/initdb --encoding=utf8 -D /data/softwares/pgsql/data\n \n# 启动 PostgreSQL 服务\n$ /data/softwares/pgsql/bin/pg_ctl -D /data/softwares/pgsql/data -l /data/softwares/pgsql/log/postgresql.log start #postgres 用户下执行\n \n# 登录 PostgreSQL 数据库\n$ psql\n\n\n4. 重启\n$ su postgres\n$ /data/softwares/pgsql/bin/pg_ctl -D /data/softwares/pgsql/data -l /data/softwares/pgsql/log/postgresql.log restart\n\n5. 设置开机启动\n解压后的 postgresql-x.x.x 下提供了基于 freebsd、linux、osx 3 个系统的 postgresql 启动命令。\n1)对于通过源码自定义安装的 pgsql,需要修改相关启动脚本:\n$ cd postgresql-10.0/postgresql-10.0/contrib/start-scripts\n$ vi linux\n......\n......\n# Installation prefix\nprefix=/data/softwares/pgsql\n \n# Data directory\nPGDATA="/data/softwares/pgsql/data"\n \n# Who to run the postmaster as, usually "postgres". (NOT "root")\nPGUSER=postgres\n \n# Where to keep a log file\nPGLOG="$PGDATA/serverlog"\n......\n......\n2)设置数据库开机启动:\n$ cp /data/softwares/source/postgresql-10.0/postgresql-10.0/contrib/start-scripts/linux /etc/init.d/postgresql\n\n# 添加执行权限\n$ chmod a+x /etc/init.d/postgresql\n\n# 添加至开机启动\n$ chkconfig --add postgresql\n$ chkconfig postgresql on\n3)查看 postgresql 状态\n$ service postgresql status\npg_ctl: server is running (PID: 32586)\n/data/softwares/pgsql/bin/postgres "-D" "/data/softwares/pgsql/data"\n6. 禁止管理员空密码登录\n在 PostgreSQL 中,如果你想禁止管理员(通常是 postgres 用户)使用空密码登录(正常情况下 postgres 用户可以直接使用 psql 命令直接登录 PostgreSQL),你可以通过修改 pg_hba.conf 文件来实现。\n\n\n找到你的 pg_hba.conf 文件。这个文件通常位于 PostgreSQL 的数据目录中,例如 /var/lib/pgsql/data 或 /etc/postgresql//main。\n\n\n修改 pg_hba.conf 文件,将管理员的登录方式从 trust 更改为 md5 或 password。这意味着所有连接,包括 postgres 用户的,都需要提供密码。\n\n\n例如,将以下行:\nlocal all postgres trust\n\n修改为:\nlocal all postgres md5\n\n\n重新加载或重启 PostgreSQL 服务以应用更改。\n\n重新加载配置的命令通常是:\npg_ctl reload\n或者重启服务:\nsystemctl restart postgresql\n或者在不同的系统中可能是:\nservice postgresql restart\n完成这些步骤后,postgres 用户将不能再使用空密码登录数据库。其他用户如果想登录数据库,也需要提供密码。', 'bodyHTML': '

PostgreSQL 是一个功能强大的开源对象关系数据库管理系统(ORDBMS),它从伯克利写的 POSTGRES 软件包发展而来(1995 年几个 UCB 的学生为 Post-Ingres 开发了 SQL 的接口,正式发布了 PostgreSQL95,随后一步步在开源社区中成长起来),经过十几年的发展, PostgreSQL 已经成为世界上发展最快最受欢迎的数据库系统之一。

\n

本文章主要介绍在 CentOS 下源码编码安装 PostgreSQL-10.0 的一些简单步骤,以供参考。

\n\n

1. 新增用户组及用户

\n

PostgreSQL 默认是通过 postgres:postgres 来启动和使用的,因此在安装 PostgreSQL 前需要先创建 postgres 用户组及 postgres 用户。

\n
# 在root权限下进行\ngroupadd postgres                    # 添加postgres用户组\nuseradd postgres -g postgres         # 添加postgres用户\npasswd postgres                      # 设置postgres用户密码
\n

2. 安装

\n
$ wget https://ftp.postgresql.org/pub/source/v10.0/postgresql-10.0.tar.gz\n$ tar zvxf postgresql-10.0.tar.gz\n$ cd postgresql-10.0\n$ ./configure --prefix=/data/softwares/pgsql\n$ make\n$ make install\n
\n

解决依赖:

\n
FAQ1:configure: error: readline library not found\n$ yum install readline-devel\n\nFAQ2:configure: error: zlib library not found\n$ yum install zlib-devel\n
\n

3. 启动

\n
# 新建数据库数据文件目录\n$ mkdir /data/softwares/pgsql/data\n \n# 新建数据库 log 文件目录\n$ mkdir /data/softwares/pgsql/log\n \n# 修改目录拥有者\n$ chown postgres:postgres /data/softwares/pgsql/data -R\n$ chown postgres:postgres /data/softwares/pgsql/log -R\n \n# 执行数据库初始化脚本\n$ su postgres\n$ /data/softwares/pgsql/bin/initdb --encoding=utf8 -D /data/softwares/pgsql/data\n \n# 启动 PostgreSQL 服务\n$ /data/softwares/pgsql/bin/pg_ctl -D /data/softwares/pgsql/data -l /data/softwares/pgsql/log/postgresql.log start    #postgres 用户下执行\n \n# 登录 PostgreSQL 数据库\n$ psql\n
\n

psql-db-list

\n

4. 重启

\n
$ su postgres\n$ /data/softwares/pgsql/bin/pg_ctl -D /data/softwares/pgsql/data -l /data/softwares/pgsql/log/postgresql.log restart\n
\n

5. 设置开机启动

\n

解压后的 postgresql-x.x.x 下提供了基于 freebsd、linux、osx 3 个系统的 postgresql 启动命令。

\n

1)对于通过源码自定义安装的 pgsql,需要修改相关启动脚本:

\n
$ cd postgresql-10.0/postgresql-10.0/contrib/start-scripts\n$ vi linux\n......\n......\n# Installation prefix\nprefix=/data/softwares/pgsql\n  \n# Data directory\nPGDATA="/data/softwares/pgsql/data"\n  \n# Who to run the postmaster as, usually "postgres".  (NOT "root")\nPGUSER=postgres\n  \n# Where to keep a log file\nPGLOG="$PGDATA/serverlog"\n......\n......
\n

2)设置数据库开机启动:

\n
$ cp /data/softwares/source/postgresql-10.0/postgresql-10.0/contrib/start-scripts/linux /etc/init.d/postgresql\n\n# 添加执行权限\n$ chmod a+x /etc/init.d/postgresql\n\n# 添加至开机启动\n$ chkconfig --add postgresql\n$ chkconfig postgresql on
\n

3)查看 postgresql 状态

\n
$ service postgresql status\npg_ctl: server is running (PID: 32586)\n/data/softwares/pgsql/bin/postgres "-D" "/data/softwares/pgsql/data"
\n

6. 禁止管理员空密码登录

\n

在 PostgreSQL 中,如果你想禁止管理员(通常是 postgres 用户)使用空密码登录(正常情况下 postgres 用户可以直接使用 psql 命令直接登录 PostgreSQL),你可以通过修改 pg_hba.conf 文件来实现。

\n
    \n
  1. \n

    找到你的 pg_hba.conf 文件。这个文件通常位于 PostgreSQL 的数据目录中,例如 /var/lib/pgsql/data/etc/postgresql/<version>/main

    \n
  2. \n
  3. \n

    修改 pg_hba.conf 文件,将管理员的登录方式从 trust 更改为 md5password。这意味着所有连接,包括 postgres 用户的,都需要提供密码。

    \n
  4. \n
\n

例如,将以下行:

\n
local   all             postgres                                trust\n
\n

修改为:

\n
local   all             postgres                                md5\n
\n
    \n
  1. 重新加载或重启 PostgreSQL 服务以应用更改。
  2. \n
\n

重新加载配置的命令通常是:

\n
pg_ctl reload
\n

或者重启服务:

\n
systemctl restart postgresql
\n

或者在不同的系统中可能是:

\n
service postgresql restart
\n

完成这些步骤后,postgres 用户将不能再使用空密码登录数据库。其他用户如果想登录数据库,也需要提供密码。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.4-数据库'}, 'labels': {'nodes': [{'name': '1.4.1-PostgreSQL'}]}, 'comments': {'nodes': []}}, {'title': 'R 包安装指定 GCC 和 G++ 并开启 C++11 支持', 'number': 85, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/85', 'createdAt': '2024-08-30T03:00:33Z', 'lastEditedAt': '2024-08-30T03:07:53Z', 'updatedAt': '2024-08-30T03:07:53Z', 'body': '如果你的 R 是使用比较低版本的 GCC(如 Red Hat 6.5 + GCC/G++ 4.4.7),但安装的 R 包需要开启 C++11 支持,或者需要更高版本的 GCC 和 G++,可以参考一下这个方法。\r\n\r\n\r\n\r\n首先,在 `home` 目录创建一个 `~/.R/Makevars` 文件。\r\n\r\n```bash\r\nmkdir ~/.R\r\nvi ~/.R/Makevars\r\n```\r\n\r\n然后,在 `Makevars` 文件中加入以下内容。\r\n\r\n```bash\r\nCXX11 = /opt/rh/devtoolset-7/root/usr/bin/g++ -std=c++11 -fPIC\r\nCXX14 = /opt/rh/devtoolset-7/root/usr/bin/g++\r\nCXX14FLAGS = -g -O2 $(LTO)\r\nCXX14PICFLAGS = -fpic\r\nCXX14STD = -std=gnu++14\r\n```\r\n\r\n最后,重新打开 R,执行对应包安装。\r\n\r\n```r\r\noptions("repos"=c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))\r\ninstall.packages("gridtext")\r\n```\r\n\r\n![install-packages-gridtext](https://kg.weiyan.cc/2024/08/install-packages-gridtext.webp)\r\n\r\n参考资料:\r\n\r\n1. [ERROR: compilation failed for package \'gridtext\' - wilkelab/gridtext#7](https://github.com/wilkelab/gridtext/issues/7)\r\n', 'bodyText': '如果你的 R 是使用比较低版本的 GCC(如 Red Hat 6.5 + GCC/G++ 4.4.7),但安装的 R 包需要开启 C++11 支持,或者需要更高版本的 GCC 和 G++,可以参考一下这个方法。\n\n首先,在 home 目录创建一个 ~/.R/Makevars 文件。\nmkdir ~/.R\nvi ~/.R/Makevars\n然后,在 Makevars 文件中加入以下内容。\nCXX11 = /opt/rh/devtoolset-7/root/usr/bin/g++ -std=c++11 -fPIC\nCXX14 = /opt/rh/devtoolset-7/root/usr/bin/g++\nCXX14FLAGS = -g -O2 $(LTO)\nCXX14PICFLAGS = -fpic\nCXX14STD = -std=gnu++14\n最后,重新打开 R,执行对应包安装。\noptions("repos"=c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))\ninstall.packages("gridtext")\n\n参考资料:\n\nERROR: compilation failed for package \'gridtext\' - wilkelab/gridtext#7', 'bodyHTML': '

如果你的 R 是使用比较低版本的 GCC(如 Red Hat 6.5 + GCC/G++ 4.4.7),但安装的 R 包需要开启 C++11 支持,或者需要更高版本的 GCC 和 G++,可以参考一下这个方法。

\n\n

首先,在 home 目录创建一个 ~/.R/Makevars 文件。

\n
mkdir ~/.R\nvi ~/.R/Makevars
\n

然后,在 Makevars 文件中加入以下内容。

\n
CXX11 = /opt/rh/devtoolset-7/root/usr/bin/g++ -std=c++11 -fPIC\nCXX14 = /opt/rh/devtoolset-7/root/usr/bin/g++\nCXX14FLAGS = -g -O2 $(LTO)\nCXX14PICFLAGS = -fpic\nCXX14STD = -std=gnu++14
\n

最后,重新打开 R,执行对应包安装。

\n
options("repos"=c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))\ninstall.packages("gridtext")
\n

install-packages-gridtext

\n

参考资料:

\n
    \n
  1. ERROR: compilation failed for package \'gridtext\' - wilkelab/gridtext#7
  2. \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '1.3.6-R'}]}, 'comments': {'nodes': []}}, {'title': '诛仙', 'number': 84, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/84', 'createdAt': '2024-08-20T03:55:13Z', 'lastEditedAt': '2024-08-20T04:23:23Z', 'updatedAt': '2024-08-20T04:23:23Z', 'body': '闲来看剧,无意中在腾讯视频看了几集《诛仙》动漫,虽然个别人物在建模还不算特别满意,但总体还是很不错,而且冲着对原著的高度还原,瞬间有种入坑不能自拔的感觉。\r\n\r\n\r\n\r\n第一次接触诛仙小说应该也是十几年前的事情,高一高二一度沉迷网络小说,一发不可收拾,断断续续的看了不少。惊叹于作者对于诛仙世界架构和故事逻辑,主副线也很完整,人物鲜活丰满,而且文笔也不错。最引人瞩目的当属主人公的感情纠葛,碧瑶的虽死不悔的爱,陆雪琪的温婉素雅和为了张小凡的付出都是让那时的我特别特别感动的,从当时来说,诛仙确实是非常可以带给人一种震撼的感觉的。 \r\n\r\n\r\n如今从动漫入局,又把原小说看了一遍,梦回青春年少的仙侠错觉,总有种说不清道不明的神奇滋味。', 'bodyText': '闲来看剧,无意中在腾讯视频看了几集《诛仙》动漫,虽然个别人物在建模还不算特别满意,但总体还是很不错,而且冲着对原著的高度还原,瞬间有种入坑不能自拔的感觉。\n\n第一次接触诛仙小说应该也是十几年前的事情,高一高二一度沉迷网络小说,一发不可收拾,断断续续的看了不少。惊叹于作者对于诛仙世界架构和故事逻辑,主副线也很完整,人物鲜活丰满,而且文笔也不错。最引人瞩目的当属主人公的感情纠葛,碧瑶的虽死不悔的爱,陆雪琪的温婉素雅和为了张小凡的付出都是让那时的我特别特别感动的,从当时来说,诛仙确实是非常可以带给人一种震撼的感觉的。\n如今从动漫入局,又把原小说看了一遍,梦回青春年少的仙侠错觉,总有种说不清道不明的神奇滋味。', 'bodyHTML': '

闲来看剧,无意中在腾讯视频看了几集《诛仙》动漫,虽然个别人物在建模还不算特别满意,但总体还是很不错,而且冲着对原著的高度还原,瞬间有种入坑不能自拔的感觉。

\n\n

第一次接触诛仙小说应该也是十几年前的事情,高一高二一度沉迷网络小说,一发不可收拾,断断续续的看了不少。惊叹于作者对于诛仙世界架构和故事逻辑,主副线也很完整,人物鲜活丰满,而且文笔也不错。最引人瞩目的当属主人公的感情纠葛,碧瑶的虽死不悔的爱,陆雪琪的温婉素雅和为了张小凡的付出都是让那时的我特别特别感动的,从当时来说,诛仙确实是非常可以带给人一种震撼的感觉的。

\n

如今从动漫入局,又把原小说看了一遍,梦回青春年少的仙侠错觉,总有种说不清道不明的神奇滋味。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '解决 GitHub 提交次数多导致仓库体积过大的问题', 'number': 83, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/83', 'createdAt': '2024-08-12T03:28:22Z', 'lastEditedAt': None, 'updatedAt': '2024-08-13T01:50:51Z', 'body': '提交代码要控制节奏,不能随心所欲,尤其是团队协作开发;如果发现 `.git` 目录太大,推荐使用 Git LFS 来管理大文件。\r\n\r\n\r\n\r\n参考以下几篇文章的解决方案:\r\n\r\n1. [被吐槽 GitHub仓 库太大,直接 600M 瘦身到 6M,这下舒服了](https://www.cnblogs.com/chengxy-nds/p/17306115.html) - 博客园\r\n2. [如何解决 GitHub 提交次数过多 .git 文件过大的问题?](https://www.zhihu.com/question/29769130) - 知乎', 'bodyText': '提交代码要控制节奏,不能随心所欲,尤其是团队协作开发;如果发现 .git 目录太大,推荐使用 Git LFS 来管理大文件。\n\n参考以下几篇文章的解决方案:\n\n被吐槽 GitHub仓 库太大,直接 600M 瘦身到 6M,这下舒服了 - 博客园\n如何解决 GitHub 提交次数过多 .git 文件过大的问题? - 知乎', 'bodyHTML': '

提交代码要控制节奏,不能随心所欲,尤其是团队协作开发;如果发现 .git 目录太大,推荐使用 Git LFS 来管理大文件。

\n\n

参考以下几篇文章的解决方案:

\n
    \n
  1. 被吐槽 GitHub仓 库太大,直接 600M 瘦身到 6M,这下舒服了 - 博客园
  2. \n
  3. 如何解决 GitHub 提交次数过多 .git 文件过大的问题? - 知乎
  4. \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '巴黎奥运', 'number': 82, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/82', 'createdAt': '2024-07-29T06:27:29Z', 'lastEditedAt': '2024-08-05T03:00:45Z', 'updatedAt': '2024-08-05T03:00:45Z', 'body': '2024 年的巴黎奥运会各项比赛正在如火如荼进行,但是在个人感官上,这一届的奥运会热度好像有点低。\r\n\r\n\r\n\r\n对于开幕式,有两点切身的感受比较深刻。一个是时间定于 7 月 27 日(星期六)凌晨,第二个是可以在电影院观看 2024 年巴黎奥运会开幕式直播。这些信息基于都是来源于自己在上班路上的听广播习惯,广州可进行奥运会开幕式观影预约的影院仅有 4 家,但需要达到最低拼场人数才可 "开团"!\r\n\r\n作为史上第一次把开幕式放在室外搞,也是首次摈弃以往步行进入体育场的传统,让运动员乘船沿着巴黎的"主干道" ——塞纳河前进。这届奥运会的确有点别出心裁。个人对于开幕式并没有什么特别值得期待的,也就事后通过各种短视频看了一下中国代表团出场、点燃圣火,以及其他零零散散的一些画面,感觉相比上一届的日本奥运会,巴黎奥运会给人印象更加深刻,文化底蕴、开放性、包容性都很不错,但也不可否认开幕式过后的各种两极分化评论,这的确也是争议性相当大的异常奥运会。\r\n\r\n奥运会最大的看点还是比赛。作为四年难得一遇的体育盛宴,各项赛程都很吸引人。\r\n\r\n个人最大的期待,还是在于羽毛球,小组赛的赛程也追了很多场,接下来依旧值得期待。跳水、游泳、排球、篮球,时间允许下肯定也是不能错过的。\r\n\r\n------\r\n\r\n记录一下那些自己看过的一些赛事,为这个夏天的运动健儿们加油。\r\n\r\n- 7 月 28 - 19:30 - 周日 篮球 | 女子小组赛 - A组(1):西班牙(90) VS 中国(89) \r\n 没顶住!女篮首战憾负西班牙! \r\n\r\n- 7 月 29 - 21:40 - 周一 羽毛球 | 男子双打小组赛 - D组(5):丹麦(2) VS 中国(0) \r\n \'badminton-0729\'\r\n\r\n- 7 月 30 - 20:30 - 周二 乒乓球 | 混合双打金牌赛:中国(4) VS 朝鲜(2) \r\n 乒乓球中国的首个奥运混双金牌!终于到手! \r\n \'ping-pong-china-korea-2024\'\r\n\r\n- 7 月 30 - 21:40 - 周二 羽毛球 | 男子双打小组赛 - D组(8):中国(2) VS 日本(0) \r\n 保木卓朗/小林优吾 vs 欧烜屹/刘雨辰,图欧组合终于赢了,不容易。 \r\n\r\n- 7 月 31 - 19:30 - 周三 篮球 | 女子小组赛 - A组(4):塞尔维亚(81) VS 中国(59) \r\n 两连败!中国女篮22分惨负塞尔维亚,看的揪心,后面两节完全被碾压! \r\n \'basketball-0731\'\r\n\r\n- 8 月 1 - 19:00 - 周四 羽毛球 | 男子双打1/4决赛(2):中国(2) VS 印尼(0) \r\n 梁王(梁伟铿/王昶) 2 比 0 胜双阿(阿尔菲安/阿迪安托),晋级巴黎奥运会 4 强! \r\n \'badminton-lw-paris-2024\'\r\n\r\n- 8 月 1 - 21:20 - 周四 羽毛球 | 男子单打16强赛(5):中国(0) VS 新加坡(2) \r\n 李诗沣 0 比 2 不敌骆建佑,脑子不够叠加勇气不够,战术执行不起来,输得不冤。。。 \r\n\r\n- 8 月 2 - 22:10 - 周五 羽毛球 | 混合双打金牌赛:中国(2)VS 韩国(0) \r\n 雅思组合(黄雅琼/郑思维)2:0 胜韩国金银组合(金元昊/郑那银),成就大满贯,圆梦巴黎!这场决赛不得不说,郑思维状态是真的好,打疯了! \r\n \'zheng-huang-paris-gold\' \r\n\r\n- 8 月 3 - 00:45 - 周六 羽毛球 | 男子单打1/4决赛(2) \r\n 爆冷,石宇奇 0-2 昆拉武特·威提讪,无缘羽毛球男单四强。第一次熬夜看的比赛,石头状态不好,战术上完全被压制,真的破防了! \r\n \'badminton-shiyuqi-paris-2024\' \r\n\r\n- 8 月 3 - 22:10 - 周六 羽毛球 | 女子双打金牌赛:中国(2)VS 中国(0) \r\n 凡尘组合(陈清晨/贾一凡)2:0 圣坛组合(谭宁/刘圣书),正如赛后她们身披国旗大喊 **"中国女双第一"**! \r\n \'badminton-women-gold-paris-2024\' \r\n\r\n- 8 月 4 - 20:30 - 周日 乒乓球 | 男子单打金牌赛 \r\n 4-1!樊振东击败莫雷加德勇夺男单冠军,成国乒第11位大满贯得主! \r\n \'fanzhendong-gold-paris-2024\'\r\n\r\n- 8 月 4 - 22:30 - 周日 羽毛球 | 男子双打金牌赛 \r\n 梁王组合(王昶/梁伟铿)1-2 惜败羚羊组合(李洋/王齐麟),遗憾摘银。接发球失误太多,加上随意挑战,顶着夺冠压力和政治压力打到决胜局的 19-21,也算尽力了! \r\n \'badminton-lw-silver-paris-2024\'\r\n\r\n\r\n ', 'bodyText': '2024 年的巴黎奥运会各项比赛正在如火如荼进行,但是在个人感官上,这一届的奥运会热度好像有点低。\n\n对于开幕式,有两点切身的感受比较深刻。一个是时间定于 7 月 27 日(星期六)凌晨,第二个是可以在电影院观看 2024 年巴黎奥运会开幕式直播。这些信息基于都是来源于自己在上班路上的听广播习惯,广州可进行奥运会开幕式观影预约的影院仅有 4 家,但需要达到最低拼场人数才可 "开团"!\n作为史上第一次把开幕式放在室外搞,也是首次摈弃以往步行进入体育场的传统,让运动员乘船沿着巴黎的"主干道" ——塞纳河前进。这届奥运会的确有点别出心裁。个人对于开幕式并没有什么特别值得期待的,也就事后通过各种短视频看了一下中国代表团出场、点燃圣火,以及其他零零散散的一些画面,感觉相比上一届的日本奥运会,巴黎奥运会给人印象更加深刻,文化底蕴、开放性、包容性都很不错,但也不可否认开幕式过后的各种两极分化评论,这的确也是争议性相当大的异常奥运会。\n奥运会最大的看点还是比赛。作为四年难得一遇的体育盛宴,各项赛程都很吸引人。\n个人最大的期待,还是在于羽毛球,小组赛的赛程也追了很多场,接下来依旧值得期待。跳水、游泳、排球、篮球,时间允许下肯定也是不能错过的。\n\n记录一下那些自己看过的一些赛事,为这个夏天的运动健儿们加油。\n\n\n7 月 28 - 19:30 - 周日 篮球 | 女子小组赛 - A组(1):西班牙(90) VS 中国(89)\n没顶住!女篮首战憾负西班牙!\n\n\n7 月 29 - 21:40 - 周一 羽毛球 | 男子双打小组赛 - D组(5):丹麦(2) VS 中国(0)\n\n\n\n7 月 30 - 20:30 - 周二 乒乓球 | 混合双打金牌赛:中国(4) VS 朝鲜(2)\n乒乓球中国的首个奥运混双金牌!终于到手!\n\n\n\n7 月 30 - 21:40 - 周二 羽毛球 | 男子双打小组赛 - D组(8):中国(2) VS 日本(0)\n保木卓朗/小林优吾 vs 欧烜屹/刘雨辰,图欧组合终于赢了,不容易。\n\n\n7 月 31 - 19:30 - 周三 篮球 | 女子小组赛 - A组(4):塞尔维亚(81) VS 中国(59)\n两连败!中国女篮22分惨负塞尔维亚,看的揪心,后面两节完全被碾压!\n\n\n\n8 月 1 - 19:00 - 周四 羽毛球 | 男子双打1/4决赛(2):中国(2) VS 印尼(0)\n梁王(梁伟铿/王昶) 2 比 0 胜双阿(阿尔菲安/阿迪安托),晋级巴黎奥运会 4 强!\n\n\n\n8 月 1 - 21:20 - 周四 羽毛球 | 男子单打16强赛(5):中国(0) VS 新加坡(2)\n李诗沣 0 比 2 不敌骆建佑,脑子不够叠加勇气不够,战术执行不起来,输得不冤。。。\n\n\n8 月 2 - 22:10 - 周五 羽毛球 | 混合双打金牌赛:中国(2)VS 韩国(0)\n雅思组合(黄雅琼/郑思维)2:0 胜韩国金银组合(金元昊/郑那银),成就大满贯,圆梦巴黎!这场决赛不得不说,郑思维状态是真的好,打疯了!\n\n\n\n8 月 3 - 00:45 - 周六 羽毛球 | 男子单打1/4决赛(2)\n爆冷,石宇奇 0-2 昆拉武特·威提讪,无缘羽毛球男单四强。第一次熬夜看的比赛,石头状态不好,战术上完全被压制,真的破防了!\n\n\n\n8 月 3 - 22:10 - 周六 羽毛球 | 女子双打金牌赛:中国(2)VS 中国(0)\n凡尘组合(陈清晨/贾一凡)2:0 圣坛组合(谭宁/刘圣书),正如赛后她们身披国旗大喊 "中国女双第一"!\n\n\n\n8 月 4 - 20:30 - 周日 乒乓球 | 男子单打金牌赛\n4-1!樊振东击败莫雷加德勇夺男单冠军,成国乒第11位大满贯得主!\n\n\n\n8 月 4 - 22:30 - 周日 羽毛球 | 男子双打金牌赛\n梁王组合(王昶/梁伟铿)1-2 惜败羚羊组合(李洋/王齐麟),遗憾摘银。接发球失误太多,加上随意挑战,顶着夺冠压力和政治压力打到决胜局的 19-21,也算尽力了!', 'bodyHTML': '

2024 年的巴黎奥运会各项比赛正在如火如荼进行,但是在个人感官上,这一届的奥运会热度好像有点低。

\n\n

对于开幕式,有两点切身的感受比较深刻。一个是时间定于 7 月 27 日(星期六)凌晨,第二个是可以在电影院观看 2024 年巴黎奥运会开幕式直播。这些信息基于都是来源于自己在上班路上的听广播习惯,广州可进行奥运会开幕式观影预约的影院仅有 4 家,但需要达到最低拼场人数才可 "开团"!

\n

作为史上第一次把开幕式放在室外搞,也是首次摈弃以往步行进入体育场的传统,让运动员乘船沿着巴黎的"主干道" ——塞纳河前进。这届奥运会的确有点别出心裁。个人对于开幕式并没有什么特别值得期待的,也就事后通过各种短视频看了一下中国代表团出场、点燃圣火,以及其他零零散散的一些画面,感觉相比上一届的日本奥运会,巴黎奥运会给人印象更加深刻,文化底蕴、开放性、包容性都很不错,但也不可否认开幕式过后的各种两极分化评论,这的确也是争议性相当大的异常奥运会。

\n

奥运会最大的看点还是比赛。作为四年难得一遇的体育盛宴,各项赛程都很吸引人。

\n

个人最大的期待,还是在于羽毛球,小组赛的赛程也追了很多场,接下来依旧值得期待。跳水、游泳、排球、篮球,时间允许下肯定也是不能错过的。

\n
\n

记录一下那些自己看过的一些赛事,为这个夏天的运动健儿们加油。

\n
    \n
  • \n

    7 月 28 - 19:30 - 周日 篮球 | 女子小组赛 - A组(1):西班牙(90) VS 中国(89)
    \n没顶住!女篮首战憾负西班牙!

    \n
  • \n
  • \n

    7 月 29 - 21:40 - 周一 羽毛球 | 男子双打小组赛 - D组(5):丹麦(2) VS 中国(0)
    \nbadminton-0729

    \n
  • \n
  • \n

    7 月 30 - 20:30 - 周二 乒乓球 | 混合双打金牌赛:中国(4) VS 朝鲜(2)
    \n乒乓球中国的首个奥运混双金牌!终于到手!
    \nping-pong-china-korea-2024

    \n
  • \n
  • \n

    7 月 30 - 21:40 - 周二 羽毛球 | 男子双打小组赛 - D组(8):中国(2) VS 日本(0)
    \n保木卓朗/小林优吾 vs 欧烜屹/刘雨辰,图欧组合终于赢了,不容易。

    \n
  • \n
  • \n

    7 月 31 - 19:30 - 周三 篮球 | 女子小组赛 - A组(4):塞尔维亚(81) VS 中国(59)
    \n两连败!中国女篮22分惨负塞尔维亚,看的揪心,后面两节完全被碾压!
    \nbasketball-0731

    \n
  • \n
  • \n

    8 月 1 - 19:00 - 周四 羽毛球 | 男子双打1/4决赛(2):中国(2) VS 印尼(0)
    \n梁王(梁伟铿/王昶) 2 比 0 胜双阿(阿尔菲安/阿迪安托),晋级巴黎奥运会 4 强!
    \nbadminton-lw-paris-2024

    \n
  • \n
  • \n

    8 月 1 - 21:20 - 周四 羽毛球 | 男子单打16强赛(5):中国(0) VS 新加坡(2)
    \n李诗沣 0 比 2 不敌骆建佑,脑子不够叠加勇气不够,战术执行不起来,输得不冤。。。

    \n
  • \n
  • \n

    8 月 2 - 22:10 - 周五 羽毛球 | 混合双打金牌赛:中国(2)VS 韩国(0)
    \n雅思组合(黄雅琼/郑思维)2:0 胜韩国金银组合(金元昊/郑那银),成就大满贯,圆梦巴黎!这场决赛不得不说,郑思维状态是真的好,打疯了!
    \nzheng-huang-paris-gold

    \n
  • \n
  • \n

    8 月 3 - 00:45 - 周六 羽毛球 | 男子单打1/4决赛(2)
    \n爆冷,石宇奇 0-2 昆拉武特·威提讪,无缘羽毛球男单四强。第一次熬夜看的比赛,石头状态不好,战术上完全被压制,真的破防了!
    \nbadminton-shiyuqi-paris-2024

    \n
  • \n
  • \n

    8 月 3 - 22:10 - 周六 羽毛球 | 女子双打金牌赛:中国(2)VS 中国(0)
    \n凡尘组合(陈清晨/贾一凡)2:0 圣坛组合(谭宁/刘圣书),正如赛后她们身披国旗大喊 "中国女双第一"
    \nbadminton-women-gold-paris-2024

    \n
  • \n
  • \n

    8 月 4 - 20:30 - 周日 乒乓球 | 男子单打金牌赛
    \n4-1!樊振东击败莫雷加德勇夺男单冠军,成国乒第11位大满贯得主!
    \nfanzhendong-gold-paris-2024

    \n
  • \n
  • \n

    8 月 4 - 22:30 - 周日 羽毛球 | 男子双打金牌赛
    \n梁王组合(王昶/梁伟铿)1-2 惜败羚羊组合(李洋/王齐麟),遗憾摘银。接发球失误太多,加上随意挑战,顶着夺冠压力和政治压力打到决胜局的 19-21,也算尽力了!
    \nbadminton-lw-silver-paris-2024

    \n
  • \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '寒冬将至', 'number': 81, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/81', 'createdAt': '2024-07-15T02:24:05Z', 'lastEditedAt': '2024-07-15T02:38:07Z', 'updatedAt': '2024-08-16T02:39:26Z', 'body': "经济不景气,就像一股寒风,吹得人心颤颤,市场更是进入严冬,就业、消费和投资都变得如履薄冰。\r\n\r\n\r\n\r\n从最近身边的很多人身上,由于大环境不景气带来的裁员比比皆是,IVD 行业、生信行业订单以肉眼可见的速度越来越少,小公司首先扛不住开启裁员,大公司从考核到绩效各种手段轮番上阵。\r\n\r\n\r\n\r\n好一点的公司 N+1 赔偿,但凤毛麟角;次一点的公司礼仪性的赔偿 1、2 个月的工资;更多的是领完当月工资走人;更有甚者,老板跑路,变相裁人的 ......\r\n\r\n裁人失业年年有,今年的暴风雨可能会更加猛烈些。铁打的营盘,流水的兵,除了比比谁更卷,还是要多思考一下自身的选择和规划。", 'bodyText': '经济不景气,就像一股寒风,吹得人心颤颤,市场更是进入严冬,就业、消费和投资都变得如履薄冰。\n\n从最近身边的很多人身上,由于大环境不景气带来的裁员比比皆是,IVD 行业、生信行业订单以肉眼可见的速度越来越少,小公司首先扛不住开启裁员,大公司从考核到绩效各种手段轮番上阵。\n\n好一点的公司 N+1 赔偿,但凤毛麟角;次一点的公司礼仪性的赔偿 1、2 个月的工资;更多的是领完当月工资走人;更有甚者,老板跑路,变相裁人的 ......\n裁人失业年年有,今年的暴风雨可能会更加猛烈些。铁打的营盘,流水的兵,除了比比谁更卷,还是要多思考一下自身的选择和规划。', 'bodyHTML': '

经济不景气,就像一股寒风,吹得人心颤颤,市场更是进入严冬,就业、消费和投资都变得如履薄冰。

\n\n

从最近身边的很多人身上,由于大环境不景气带来的裁员比比皆是,IVD 行业、生信行业订单以肉眼可见的速度越来越少,小公司首先扛不住开启裁员,大公司从考核到绩效各种手段轮番上阵。

\n

\n

好一点的公司 N+1 赔偿,但凤毛麟角;次一点的公司礼仪性的赔偿 1、2 个月的工资;更多的是领完当月工资走人;更有甚者,老板跑路,变相裁人的 ......

\n

裁人失业年年有,今年的暴风雨可能会更加猛烈些。铁打的营盘,流水的兵,除了比比谁更卷,还是要多思考一下自身的选择和规划。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': [{'body': '更加艰难了', 'author': {'login': 'obaby'}}]}}, {'title': '晒桌面', 'number': 80, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/80', 'createdAt': '2024-07-08T03:43:13Z', 'lastEditedAt': None, 'updatedAt': '2024-07-08T03:43:14Z', 'body': '文艺男青年对于烟火气息的干净整洁桌面总有一种迷之吸引,热衷于各种晒桌面带来的解压感,其中的细节让我觉得这才是生活应该有的部分,尤其在这样的桌面上摆上各种我喜欢的影音娱乐设备,更能点亮我的生活。\r\n\r\n', 'bodyText': '文艺男青年对于烟火气息的干净整洁桌面总有一种迷之吸引,热衷于各种晒桌面带来的解压感,其中的细节让我觉得这才是生活应该有的部分,尤其在这样的桌面上摆上各种我喜欢的影音娱乐设备,更能点亮我的生活。', 'bodyHTML': '

文艺男青年对于烟火气息的干净整洁桌面总有一种迷之吸引,热衷于各种晒桌面带来的解压感,其中的细节让我觉得这才是生活应该有的部分,尤其在这样的桌面上摆上各种我喜欢的影音娱乐设备,更能点亮我的生活。

\n', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'Python 陷阱之 strip、lstrip、rstrip 可以删除比预期更多的内容', 'number': 79, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/79', 'createdAt': '2024-07-03T08:05:40Z', 'lastEditedAt': None, 'updatedAt': '2024-07-03T08:05:40Z', 'body': '> 原文:[Python Gotcha: strip, lstrip, rstrip can remove more than expected](https://andrewwegner.com/python-gotcha-strip-functions-unexpected-behavior.html)\r\n\r\n## 介绍\r\n\r\n作为一名软件工程师,你处理过不少脏字符串。删除用户输入中的前导或尾随空格可能是最常见的工作之一。\r\n\r\n在 Python 中,这是通过 `.strip()` 、 `.lstrip()` 或 `.rstrip()` 函数完成的,通常如下所示:\r\n```python\r\n>>> " Andrew Wegner ".lower().strip()\r\n\'andrew wegner\'\r\n>>> " Andrew Wegner ".lower().lstrip()\r\n\'andrew wegner \'\r\n>>> " Andrew Wegner ".lower().rstrip()\r\n\' andrew wegner\'\r\n```\r\n\r\n这非常简单,并且没有什么意外的事情发生。\r\n\r\n## 陷阱\r\n\r\n陷阱在于,这些函数中的每一个都可以接受一个要删除的字符列表。\r\n\r\n```python\r\n>>> "Andrew Wegner".lower().rstrip(" wegner")\r\n\'and\'\r\n```\r\n\r\n发生了什么?为什么结果不只是:\r\n```bash\r\n\'andrew\'\r\n```\r\n\r\n## 解释\r\n\r\n再次仔细阅读文档中的这行说明:\r\n\r\n> A list of **characters**\r\n\r\n不是字符串列表 (Not a list of strings.)。\r\n\r\n> [str.rstrip([chars])](https://docs.python.org/3/library/stdtypes.html#str.rstrip)\r\n> \r\n> Return a copy of the string with trailing characters removed. The chars argument is a string specifying the set of characters to be removed. If omitted or `None`, the chars argument defaults to removing whitespace. The chars argument is **not a suffix**; rather, **all combinations of its values are stripped**.\r\n> \r\n> From [Built-in Types — Python 3.12.4 documentation](https://docs.python.org/3/library/stdtypes.html)\r\n\r\n文档中已经明确并举例说明了这一行为及其含义。然而,对于新开发者来说,这是出乎意料的行为。毕竟,这些函数看起来都很直观。\r\n\r\n我的示例执行以下操作:\r\n', 'bodyText': '原文:Python Gotcha: strip, lstrip, rstrip can remove more than expected\n\n介绍\n作为一名软件工程师,你处理过不少脏字符串。删除用户输入中的前导或尾随空格可能是最常见的工作之一。\n在 Python 中,这是通过 .strip() 、 .lstrip() 或 .rstrip() 函数完成的,通常如下所示:\n>>> " Andrew Wegner ".lower().strip()\n\'andrew wegner\'\n>>> " Andrew Wegner ".lower().lstrip()\n\'andrew wegner \'\n>>> " Andrew Wegner ".lower().rstrip()\n\' andrew wegner\'\n这非常简单,并且没有什么意外的事情发生。\n陷阱\n陷阱在于,这些函数中的每一个都可以接受一个要删除的字符列表。\n>>> "Andrew Wegner".lower().rstrip(" wegner")\n\'and\'\n发生了什么?为什么结果不只是:\n\'andrew\'\n解释\n再次仔细阅读文档中的这行说明:\n\nA list of characters\n\n不是字符串列表 (Not a list of strings.)。\n\nstr.rstrip([chars])\nReturn a copy of the string with trailing characters removed. The chars argument is a string specifying the set of characters to be removed. If omitted or None, the chars argument defaults to removing whitespace. The chars argument is not a suffix; rather, all combinations of its values are stripped.\nFrom Built-in Types — Python 3.12.4 documentation\n\n文档中已经明确并举例说明了这一行为及其含义。然而,对于新开发者来说,这是出乎意料的行为。毕竟,这些函数看起来都很直观。\n我的示例执行以下操作:', 'bodyHTML': '
\n

原文:Python Gotcha: strip, lstrip, rstrip can remove more than expected

\n
\n

介绍

\n

作为一名软件工程师,你处理过不少脏字符串。删除用户输入中的前导或尾随空格可能是最常见的工作之一。

\n

在 Python 中,这是通过 .strip().lstrip().rstrip() 函数完成的,通常如下所示:

\n
>>> "     Andrew Wegner     ".lower().strip()\n\'andrew wegner\'\n>>> "     Andrew Wegner     ".lower().lstrip()\n\'andrew wegner     \'\n>>> "     Andrew Wegner     ".lower().rstrip()\n\'     andrew wegner\'
\n

这非常简单,并且没有什么意外的事情发生。

\n

陷阱

\n

陷阱在于,这些函数中的每一个都可以接受一个要删除的字符列表。

\n
>>> "Andrew Wegner".lower().rstrip(" wegner")\n\'and\'
\n

发生了什么?为什么结果不只是:

\n
\'andrew\'
\n

解释

\n

再次仔细阅读文档中的这行说明:

\n
\n

A list of characters

\n
\n

不是字符串列表 (Not a list of strings.)。

\n
\n

str.rstrip([chars])

\n

Return a copy of the string with trailing characters removed. The chars argument is a string specifying the set of characters to be removed. If omitted or None, the chars argument defaults to removing whitespace. The chars argument is not a suffix; rather, all combinations of its values are stripped.

\n

From Built-in Types — Python 3.12.4 documentation

\n
\n

文档中已经明确并举例说明了这一行为及其含义。然而,对于新开发者来说,这是出乎意料的行为。毕竟,这些函数看起来都很直观。

\n

我的示例执行以下操作:

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.2-编程'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '手机', 'number': 78, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/78', 'createdAt': '2024-06-25T07:05:40Z', 'lastEditedAt': None, 'updatedAt': '2024-06-25T07:05:40Z', 'body': '手机对大部分人来说,现在更像是一个外置的私密部位:能随意触碰的人只有自己,伴侣想碰也得防着,只有万不得已的时候,才能交到专业人士手上(指修手机的)。\r\n\r\n', 'bodyText': '手机对大部分人来说,现在更像是一个外置的私密部位:能随意触碰的人只有自己,伴侣想碰也得防着,只有万不得已的时候,才能交到专业人士手上(指修手机的)。', 'bodyHTML': '

手机对大部分人来说,现在更像是一个外置的私密部位:能随意触碰的人只有自己,伴侣想碰也得防着,只有万不得已的时候,才能交到专业人士手上(指修手机的)。

\n', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '最舒服的字号和字体大小', 'number': 77, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/77', 'createdAt': '2024-06-18T02:19:36Z', 'lastEditedAt': '2024-06-18T02:24:11Z', 'updatedAt': '2024-06-18T02:24:11Z', 'body': '最舒服的字号目前没有确切的定论,默认的微软雅黑还能接受。但是在字体大小这一块,个人对小字体情有独钟。\r\n\r\n\r\n\r\n在手机端一直都会把系统(或者是常用 APP)的字体设置为最小,很重要的一个原因就是能在一页上容纳更多的信息,排版布局看起来更加舒服。在知乎看到有人说喜欢用小字体的人,其性格可能会相对内向,日常生活中并不是特别外向开放的人,或许也有一定的道理。\r\n\r\n浏览器端最常用的 Google Chrome 和备用的 Edge 用的也是 **14px** 的字体大小。 \r\n\r\n![chrome-14px](https://kg.weiyan.cc/2024/06/chrome-14px.png)', 'bodyText': '最舒服的字号目前没有确切的定论,默认的微软雅黑还能接受。但是在字体大小这一块,个人对小字体情有独钟。\n\n在手机端一直都会把系统(或者是常用 APP)的字体设置为最小,很重要的一个原因就是能在一页上容纳更多的信息,排版布局看起来更加舒服。在知乎看到有人说喜欢用小字体的人,其性格可能会相对内向,日常生活中并不是特别外向开放的人,或许也有一定的道理。\n浏览器端最常用的 Google Chrome 和备用的 Edge 用的也是 14px 的字体大小。', 'bodyHTML': '

最舒服的字号目前没有确切的定论,默认的微软雅黑还能接受。但是在字体大小这一块,个人对小字体情有独钟。

\n\n

在手机端一直都会把系统(或者是常用 APP)的字体设置为最小,很重要的一个原因就是能在一页上容纳更多的信息,排版布局看起来更加舒服。在知乎看到有人说喜欢用小字体的人,其性格可能会相对内向,日常生活中并不是特别外向开放的人,或许也有一定的道理。

\n

浏览器端最常用的 Google Chrome 和备用的 Edge 用的也是 14px 的字体大小。

\n

chrome-14px

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '生活的后花园', 'number': 76, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/76', 'createdAt': '2024-06-12T03:34:57Z', 'lastEditedAt': '2024-08-22T02:07:10Z', 'updatedAt': '2024-08-22T02:07:10Z', 'body': '年纪越大,越期待短暂的一些独处时光,安静且惬意。\r\n\r\n不知道大家的后花园都是什么,在 V2EX 看到,对有些人来说,备菜+做饭的一个小时,不接收外界信息,完全沉浸在只有自己的世界里,是他近几年找到了最好的放松方式了。对我自己可能就在于游戏+看电影,但是能有这样时间的机会确实不多。\r\n\r\n\r\n\r\n看到有人说家里玩游戏会有压力,这一点是同意的,尤其有了娃以后,放空自己的机会就更少了。所以,建立自己的精神后花园,去运运动其实也是一个不错的选择。', 'bodyText': '年纪越大,越期待短暂的一些独处时光,安静且惬意。\n不知道大家的后花园都是什么,在 V2EX 看到,对有些人来说,备菜+做饭的一个小时,不接收外界信息,完全沉浸在只有自己的世界里,是他近几年找到了最好的放松方式了。对我自己可能就在于游戏+看电影,但是能有这样时间的机会确实不多。\n\n看到有人说家里玩游戏会有压力,这一点是同意的,尤其有了娃以后,放空自己的机会就更少了。所以,建立自己的精神后花园,去运运动其实也是一个不错的选择。', 'bodyHTML': '

年纪越大,越期待短暂的一些独处时光,安静且惬意。

\n

不知道大家的后花园都是什么,在 V2EX 看到,对有些人来说,备菜+做饭的一个小时,不接收外界信息,完全沉浸在只有自己的世界里,是他近几年找到了最好的放松方式了。对我自己可能就在于游戏+看电影,但是能有这样时间的机会确实不多。

\n\n

看到有人说家里玩游戏会有压力,这一点是同意的,尤其有了娃以后,放空自己的机会就更少了。所以,建立自己的精神后花园,去运运动其实也是一个不错的选择。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': [{'body': '其实我们需要的是随心所欲的生活片段。', 'author': {'login': 'immelon0097'}}]}}, {'title': '使用 Python 的 argparse 构建命令行界面', 'number': 75, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/75', 'createdAt': '2024-06-06T06:23:52Z', 'lastEditedAt': '2024-06-07T08:35:09Z', 'updatedAt': '2024-06-07T08:35:09Z', 'body': '> 原文:[Build Command-Line Interfaces With Python\'s argparse](https://realpython.com/command-line-interfaces-python-argparse/) \r\n\r\n\r\n命令行应用在普通用户空间中可能并不常见,但它们存在于开发、数据科学、系统管理和许多其他操作中。每个命令行应用都需要一个用户友好的命令行界面 (CLI),以便你可以与应用本身进行交互。在 Python 中,您可以使用标准库中的 `argparse` 模块创建功能齐全的 CLI。\r\n\r\n\r\n\r\n在本文中,你将了解如何: \r\n\r\n- 命令行界面入门;\r\n- 在 Python 中组织和布局命令行应用项目;\r\n- 使用 Python `argparse` 创建命令行界面(command-line interfaces);\r\n- 使用 `argparse` 一些强大的功能深度自定义您的 CLI;\r\n\r\n若要充分利用本教程,应熟悉 Python 编程,包括面向对象编程、脚本开发和执行以及 Python 包和模块等概念。如果您熟悉与使用命令行或终端相关的一般概念和主题,这也将很有帮助。\r\n\r\n## 了解命令行界面\r\n\r\n自从计算机发明以来,人类一直需要并找到与这些机器交互和共享信息的方法。信息交换在人、计算机软件和硬件组件之间流动。其中任意两个元素之间的共享边界通常称为接口([interface](https://en.wikipedia.org/wiki/Interface_(computing)))。\r\n\r\n在软件开发中,接口是给定软件的特殊部分,它允许计算机系统组件之间的交互。当涉及到人机交互和软件交互时,这个重要的组件被称为用户界面([user interface](https://en.wikipedia.org/wiki/User_interface))。\r\n\r\n您会在编程中找到不同类型的用户界面。图形用户界面 (GUI) 可能是当今最常见的。但是,您还可以找到为其用户提供命令行界面 (CLI) 的应用和程序。在本教程中,你将了解 CLI 以及如何在 Python 中创建它们。\r\n\r\n## 命令行界面 (CLI)\r\n\r\n命令行界面允许您通过操作系统命令行、终端或控制台与应用程序或程序进行交互。\r\n\r\n要了解命令行界面及其工作原理,请考虑此实际示例。假设您有一个名为 sample 包含三个示例文件的目录。如果您使用的是类 Unix 操作系统,例如 Linux 或 macOS,请继续在父目录中打开命令行窗口或终端,然后执行以下命令: \r\n```bash\r\n$ ls sample/\r\nhello.txt lorem.md realpython.md\r\n```\r\n\r\nUnix 的 `ls` 命令列出目标目录中包含的文件和子目录,该目录默认为当前工作目录。上面的命令调用没有显示有关 的内容 sample 的太多信息。它只在屏幕上显示文件名。\r\n\r\n假设你想要获取有关目录及其内容的更丰富信息,那么你不需要寻找其他程序,因为 ls 命令有一个功能齐全的命令行界面,并且提供了一组有用的选项,可以用来定制命令的行为。\r\n\r\n例如,继续执行带有 `-l` 选项的 `ls` 命令: \r\n```bash\r\n$ ls -l sample/\r\ntotal 24\r\n-rw-r--r--@ 1 user staff 83 Aug 17 22:15 hello.txt\r\n-rw-r--r--@ 1 user staff 2609 Aug 17 22:15 lorem.md\r\n-rw-r--r--@ 1 user staff 428 Aug 17 22:15 realpython.md\r\n```\r\n\r\n现在,`ls` 命令的输出完全不同了。该命令显示了有关 sample 目录中文件的更多信息,包括权限、所有者、组、日期和大小。它还显示了这些文件在你计算机磁盘上使用的总空间。\r\n\r\n这种更丰富的输出结果是由于使用了 `-l` 选项,这是 Unix `ls` 命令行界面的一部分,它启用了详细的输出格式。\r\n\r\n## 命令、参数、选项、参数和子命令\r\n\r\n在本教程中,您将深入了解**命令**(commands)及其**子命令**(subcommands),同时还会学习到**命令行参数**(command-line arguments)、**选项**(options)和**参数**(parameters)的相关知识。因此,建议您将这些术语纳入您的技术词汇库中。\r\n\r\n- **命令(Command)**:在命令行或终端窗口中运行的程序或例程。通常,您可以通过其背后的程序(underlying program)或例程(routine)的名称来识别一个命令。 \r\n- **参数(Argument)**:命令在执行其预期操作时所需或可选的信息片段。命令通常接受一个或多个参数,您可以在命令行中以空格分隔或逗号分隔的列表形式提供这些参数。 \r\n- **选项(Option)**,也称为 **flag** 或 **switch**:一种可选的参数,用于修改命令的行为。选项通过特定的名称(如前一个示例中的 `-l`)传递给命令。 \r\n- **参数(Parameter)**:一个选项用于执行其预期操作或动作时所使用的参数。 \r\n- 子命令(Subcommand)**:一个预定义的名称,可以传递给应用程序来执行特定的操作。\r\n\r\n参考上一节中的示例命令结构:\r\n```bash\r\n$ ls -l sample/\r\n```\r\n\r\n在这个例子中,您组合了命令行界面(CLI)的以下组件: \r\n\r\n- **ls**:命令的名称或应用的名称;\r\n- **-l**:启用详细输出的选项(option)、开关(switch)或标志(flag); \r\n- **sample**:为命令执行提供附加信息的参数(argument); \r\n\r\n现在,让我们来看下面的命令结构,它展示了 Python 包管理器 `pip` 的命令行界面(CLI): \r\n```bash\r\n$ pip install -r requirements.txt\r\n```\r\n\r\n这是一个常见的 `pip` 命令结构,您可能之前已经见过。它允许您使用 `requirements.txt` 文件来给指定的 Python 项目安装依赖项。在这个例子中,您使用了以下命令行界面(CLI)组件: \r\n \r\n- **pip**:命令的名称;\r\n- **install**:`pip` 的子命令(subcommand)名称;\r\n- **-r**:`install` 子命令的选项(option);\r\n- **requirements.txt**:一个参数,特别是 `-r` 选项的参数。\r\n\r\n现在您已经了解了命令行界面(CLI)是什么以及其主要部分或组件有哪些。接下来,是时候学习如何在 Python 中创建自己的 CLI 了。\r\n\r\n## Python 中的 CLI 入门\r\n\r\nPython 附带了一些工具,这些工具可帮助您为程序和应用程序编写命令行界面(CLI)。若您需要快速为小型程序构建一个简洁的 CLI,那么可以利用 [`sys`](https://docs.python.org/3/library/sys.html#module-sys) 模块中的 [`argv`](https://docs.python.org/3/library/sys.html#sys.argv) 属性。这个属性会自动存储您在命令行中传递给特定程序的参数。\r\n\r\n### 使用 `sys.argv` 构建最小的 CLI\r\n\r\n以使用 `argv` 创建最小命令行界面(CLI)为例,假设您需要编写一个小程序,该程序类似于 `ls` 命令,能够列出给定目录下的所有文件。在这种情况下,您可以编写如下代码: \r\n```python\r\n# ls_argv.py\r\n\r\nimport sys\r\nfrom pathlib import Path\r\n\r\nif (args_count := len(sys.argv)) > 2:\r\n print(f"One argument expected, got {args_count - 1}")\r\n raise SystemExit(2)\r\nelif args_count < 2:\r\n print("You must specify the target directory")\r\n raise SystemExit(2)\r\n\r\ntarget_dir = Path(sys.argv[1])\r\n\r\nif not target_dir.is_dir():\r\n print("The target directory doesn\'t exist")\r\n raise SystemExit(1)\r\n\r\nfor entry in target_dir.iterdir():\r\n print(entry.name)\r\n```\r\n\r\n该程序通过手动处理命令行提供的参数来实现了一个简单的命令行界面(CLI),这些参数会自动存储在 `sys.argv` 中。`sys.argv` 的第一个元素始终是程序名称,第二个元素则是目标目录。由于应用程序不应接受超过一个目标目录,因此 `args_count` 不得超过 2。\r\n\r\n在检查 `sys.argv` 的内容后,您创建一个`pathlib.Path`对象来存储目标目录的路径。如果该目录不存在,您将通知用户并退出程序。接下来的`for`循环将列出目录内容,每行一个条目。\r\n\r\n如果从命令行运行该脚本,您将得到以下结果: \r\n```bash\r\n$ python ls_argv.py sample/\r\nhello.txt\r\nlorem.md\r\nrealpython.md\r\n\r\n$ python ls_argv.py\r\nYou must specify the target directory\r\n\r\n$ python ls_argv.py sample/ other_dir/\r\nOne argument expected, got 2\r\n\r\n$ python ls_argv.py non_existing/\r\nThe target directory doesn\'t exist\r\n```\r\n\r\n您的程序接受一个目录作为参数,并列出其内容。如果您运行命令时没有提供参数,您将收到一个错误消息。如果您运行命令时指定了超过一个目标目录,您同样会收到一个错误消息。如果尝试运行命令并指定一个不存在的目录,程序将输出另一个错误消息。\r\n\r\n虽然您的程序运行正常,但对于更复杂的 CLI 应用程序来说,使用`sys.argv`属性手动解析命令行参数并不是一个可扩展的解决方案。如果您的应用需要接受更多的参数和选项,那么解析`sys.argv`将变得复杂且容易出错。您需要一个更好的解决方案,这就是 Python 中的`argparse`模块所提供的。\r\n\r\n### 使用 `argparse` 创建 CLI\r\n\r\n在 Python 中创建 CLI 应用程序的更便捷方法是使用标准库中的 [`argparse`](https://docs.python.org/3/library/argparse.html?highlight=argparse#module-argparse) 模块。该模块首次在 Python 3.2 中随 [PEP-389](https://www.python.org/dev/peps/pep-0389/) 一同发布,是快速创建 Python CLI 应用程序的利器,无需安装如 Typer 或 Click 这样的第三方库。\r\n\r\n`argparse` 模块是作为较旧的 [`getopt`](https://docs.python.org/3/library/getopt.html) 和 [`optparse`](https://docs.python.org/3/library/optparse.html) 模块的替代品而发布的,因为它们缺乏一些重要的功能。\r\n\r\nPython 的 `argparse` 模块允许您: \r\n\r\n- 解析命令行**参数**(arguments)和**选项**(options);\r\n- 在一个单一选项中接受**可变数量的参数**(variable number of parameters);\r\n- 在 CLI 中提供子命令(subcommands)。\r\n\r\n这些特性使 `argparse` 成为了一个强大的 CLI 框架,您在创建 CLI 应用程序时可以放心地依赖它。要使用 Python 的 `argparse`,您需要遵循以下四个简单的步骤:\r\n\r\n1. 导入 `argparse`;\r\n2. 通过实例化 [`ArgumentParser`](https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser) 创建**参数解析器**(argument parser);\r\n3. 使用 [`.add_argument()`](https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.add_argument) 方法向解析器添加**参数**(arguments)和**选项**(options);\r\n4. 在解析器上调用 [`.parse_args()`](https://docs.python.org/3/library/argparse.html?highlight=argparse#argparse.ArgumentParser.parse_args) 以获取参数 [`Namespace`](https://docs.python.org/3/library/argparse.html#namespace)。\r\n\r\n例如,您可以使用 `argparse` 来改进您的 `ls_argv.py` 脚本。现在,您可以创建一个名为 `ls.py` 的脚本,并编写以下代码:\r\n```python\r\n# ls.py v1\r\n\r\nimport argparse\r\nfrom pathlib import Path\r\n\r\nparser = argparse.ArgumentParser()\r\n\r\nparser.add_argument("path")\r\n\r\nargs = parser.parse_args()\r\n\r\ntarget_dir = Path(args.path)\r\n\r\nif not target_dir.exists():\r\n print("The target directory doesn\'t exist")\r\n raise SystemExit(1)\r\n\r\nfor entry in target_dir.iterdir():\r\n print(entry.name)\r\n```\r\n\r\n随着 `argparse` 的引入,您的代码发生了显著的变化。与之前的版本相比,最明显的不同是,用于检查用户提供的参数的条件语句已经消失了。这是因为 `argparse` 会自动为您检查参数的存在性。\r\n\r\n在这个新的实现中,您首先导入 `argparse` 并创建一个参数解析器。要创建解析器,您可以使用 `ArgumentParser` 类。接下来,您定义一个名为 `path` 的参数,用于获取用户的目标目录。\r\n\r\n接下来,您需要调用 `.parse_args()` 方法来解析输入参数,并获取一个包含所有用户参数的 `Namespace` 对象。请注意,现在 `args` 变量保存了一个 `Namespace` 对象,该对象具有从命令行收集的每个参数所对应的属性。\r\n\r\n在这个例子中,您只有一个参数,名为 `path`。`Namespace` 对象允许您使用点表示法通过 `args` 来访问 `path`。其余的代码与第一个实现相同。\r\n\r\n现在继续从命令行运行这个新脚本:\r\n```bash\r\n$ python ls.py sample/\r\nlorem.md\r\nrealpython.md\r\nhello.txt\r\n\r\n$ python ls.py\r\nusage: ls.py [-h] path\r\nls.py: error: the following arguments are required: path\r\n\r\n$ python ls.py sample/ other_dir/\r\nusage: ls.py [-h] path\r\nls.py: error: unrecognized arguments: other_dir/\r\n\r\n$ python ls.py non_existing/\r\nThe target directory doesn\'t exist\r\n```\r\n\r\n第一个命令的输出与您的原始脚本 `ls_argv.py` 相同。而第二个命令的输出则与 `ls_argv.py` 中的输出大不相同。程序现在会显示一个使用说明消息,并发出错误提示,告诉您必须提供 `path` 参数。\r\n\r\n在第三个命令中,您传递了两个目标目录,但应用程序并未为此做好准备。因此,它再次显示使用说明消息,并抛出一个错误,告知您潜在的问题。\r\n\r\n最后,如果您运行脚本时传递了一个不存在的目录作为参数,那么您会收到一个错误,告知您目标目录不存在,因此程序无法执行其工作。\r\n\r\n现在,您可以使用一个新的隐式特性。现在,您的程序接受一个可选的 `-h` 标志。不妨尝试一下:\r\n```bash\r\n$ python ls.py -h\r\nusage: ls.py [-h] path\r\n\r\npositional arguments:\r\n path\r\n\r\noptions:\r\n -h, --help show this help message and exit\r\n```\r\n\r\n太棒了,现在您的程序会自动响应 `-h` 或 `--help` 标志,并为您显示带有使用说明的帮助消息。这真是一个很棒的特性,而且您只需在代码中引入 `argparse` 就能轻松获得!\r\n\r\n经过这个快速介绍如何在 Python 中创建 CLI 应用后,您现在就可以深入研究 `argparse` 模块及其所有炫酷特性了。\r\n\r\n## 使用 Python 的 argparse 创建 CLI\r\n\r\n您可以使用 `argparse` 模块为您的应用程序和项目编写用户友好的命令行界面。该模块允许您定义应用程序所需的参数和选项。然后,`argparse` 将负责为您解析 `sys.argv` 的参数和选项。\r\n\r\n`argparse` 的另一个酷炫特性是它可以自动为您的 CLI 应用程序生成使用说明和帮助消息。该模块还会在参数无效时发出错误提示,并具备更多功能。\r\n\r\n在深入研究 `argparse` 之前,您需要知道该模块的文档可识别两种不同类型的命令行参数: \r\n\r\n- **位置参数**(Positional arguments),您称为参数(arguments);\r\n- **可选参数**(Optional arguments),即选项(options)、标志(flags)或开关(switches)。\r\n\r\n在 `ls.py` 的示例中,`path` 是一个**位置参数**(positional argument)。这样的参数之所以被称为位置参数,是因为它在命令构造中的相对位置定义了其作用。\r\n\r\n与位置参数不同,**可选参数**(Optional arguments)并不是必需的。它们允许你修改命令的行为。以 Unix 命令 `ls` 为例,`-l` 标志就是一个可选参数,它使得命令以详细模式显示输出。\r\n\r\n在明确了这些概念之后,你就可以着手使用 Python 和 `argparse` 库来构建自己的命令行界面(CLI)应用程序了。\r\n\r\n### 创建命令行参数解析器\r\n\r\n命令行参数解析器是任何使用 `argparse` 的命令行界面(CLI)中最为关键的部分。你在命令行上提供的所有参数和选项都会经过这个解析器的处理,它会为你完成繁重的解析工作。\r\n\r\n要使用 `argparse` 创建命令行参数解析器,您需要实例化 [`ArgumentParser`](https://docs.python.org/3/library/argparse.html#argumentparser-objects) 类: \r\n```python\r\n>>> from argparse import ArgumentParser\r\n\r\n>>> parser = ArgumentParser()\r\n>>> parser\r\nArgumentParser(\r\n prog=\'\',\r\n usage=None,\r\n description=None,\r\n formatter_class=,\r\n conflict_handler=\'error\',\r\n add_help=True\r\n)\r\n```\r\n\r\n`ArgumentParser` 的构造函数接受多种不同的参数,你可以利用这些参数来微调你的 CLI 的多个特性。由于所有这些参数都是可选的,因此你可以通过不传入任何参数直接实例化 `ArgumentParser` 来创建一个最基本的解析器。\r\n\r\n在本教程中,你将会更深入地了解 `ArgumentParser` 构造函数的参数,特别是在定制你的参数解析器的部分。目前,你可以开始使用 `argparse` 创建 CLI 的下一步了。这一步就是通过解析器对象来添加参数和选项。\r\n\r\n### 添加参数和选项\r\n\r\n要为 `argparse` 的 CLI 添加参数和选项,你将使用 `ArgumentParser` 实例的 [`.add_argument()`](https://docs.python.org/3/library/argparse.html#the-add-argument-method) 方法。请注意,这个方法对参数和选项都是通用的。在 `argparse` 的术语中,参数被称为**位置参数**(positional arguments),而选项被称为**可选参数**(optional arguments)。\r\n\r\n`.add_argument()` 方法的第一个参数决定了参数和选项之间的区别。这个参数被标识为[名称(name)或标志(flag)](https://docs.python.org/3/library/argparse.html?highlight=argparse#name-or-flags)。因此,如果你提供一个 name,那么你将定义一个参数(argument)。相反,如果你使用一个 flag,那么你将添加一个选项(option)。\r\n\r\n你已经在使用 `argparse` 时处理过命令行参数了。现在,考虑以下你自定义的 `ls` 命令的增强版本,它向 CLI 添加了一个 `-l` 选项: \r\n```python\r\n# ls.py v2\r\n\r\nimport argparse\r\nimport datetime\r\nfrom pathlib import Path\r\n\r\nparser = argparse.ArgumentParser()\r\n\r\nparser.add_argument("path")\r\n\r\nparser.add_argument("-l", "--long", action="store_true")\r\n\r\nargs = parser.parse_args()\r\n\r\ntarget_dir = Path(args.path)\r\n\r\nif not target_dir.exists():\r\n print("The target directory doesn\'t exist")\r\n raise SystemExit(1)\r\n\r\ndef build_output(entry, long=False):\r\n if long:\r\n size = entry.stat().st_size\r\n date = datetime.datetime.fromtimestamp(\r\n entry.stat().st_mtime).strftime(\r\n "%b %d %H:%M:%S"\r\n )\r\n return f"{size:>6d} {date} {entry.name}"\r\n return entry.name\r\n\r\nfor entry in target_dir.iterdir():\r\n print(build_output(entry, long=args.long))\r\n```\r\n\r\n在这个例子中,第 11 行代码创建了一个带有 `-l` 和 `--long` 标志的选项。参数(arguments)和选项(options)在语法上的区别在于,选项名称以短横线 `-` 开头表示简写标志,以双短横线 `--` 开头表示完整标志。\r\n\r\n请注意,在这个特定例子中,与 `-l` 或 `--long` 选项一同设置了一个 `action` 参数为 `"store_true"`,这意味着这个选项将存储一个布尔值。如果你在命令行上提供了这个选项,那么它的值将为 `True`。如果你省略了这个选项,那么它的值将为 `False`。在 "设置 Option 背后的 Action" 部分内容中,你将了解更多关于 `.add_argument()` 中的 `action` 参数的信息。\r\n\r\n在第 21 行的 `build_output()` 函数中,当 `long` 为 `True` 时,它会返回一个详细的输出,否则返回一个简短的输出。详细的输出将包含目标目录中所有条目的大小、修改日期和名称。它使用了诸如 `Path.stat()` 这样的工具,以及带有自定义字符串格式的 `datetime.datetime` 对象。\r\n\r\n继续在 `sample` 上执行您的程序,以检查 `-l` 选项如何工作: \r\n```bash\r\n$ python ls.py -l sample/\r\n 2609 Oct 28 14:07:04 lorem.md\r\n 428 Oct 28 14:07:04 realpython.md\r\n 83 Oct 28 14:07:04 hello.txt\r\n```\r\n\r\n新增的 `-l` 选项允许你生成并显示关于目标目录内容的更详细输出。\r\n\r\n既然你已经知道了如何向 CLI 添加命令行参数和选项,接下来就是深入解析这些参数和选项的时候了。这将是你在接下来部分要探索的内容。\r\n\r\n### 解析命令行参数和选项\r\n\r\n解析命令行参数是基于 `argparse` 的任何 CLI 应用中的另一个重要步骤。一旦你解析了参数,你就可以根据它们的值来执行相应的操作。在你自定义的 `ls` 命令示例中,参数解析发生在包含 `args = parser.parse_args()` 语句的行上。\r\n\r\n这个语句调用了 [`.parse_args()`](https://docs.python.org/3/library/argparse.html#the-parse-args-method) 方法,并将其返回值赋给 `args` 变量。`.parse_args()` 的返回值是一个 [`Namespace`](https://docs.python.org/3/library/argparse.html#the-namespace-object) 对象,其中包含了在命令行上提供的所有参数和选项以及它们对应的值。\r\n\r\n考虑以下简单的示例: \r\n```python\r\n>>> from argparse import ArgumentParser\r\n\r\n>>> parser = ArgumentParser()\r\n\r\n>>> parser.add_argument("site")\r\n_StoreAction(...)\r\n\r\n>>> parser.add_argument("-c", "--connect", action="store_true")\r\n_StoreTrueAction(...)\r\n\r\n>>> args = parser.parse_args(["Real Python", "-c"])\r\n>>> args\r\nNamespace(site=\'Real Python\', connect=True)\r\n\r\n>>> args.site\r\n\'Real Python\'\r\n>>> args.connect\r\nTrue\r\n```\r\n\r\n通过在命令行参数解析器上调用 `.parse_args()` 方法得到的 `Namespace` 对象,你可以使用**点表示法**(dot notation)访问所有输入参数、选项以及它们对应的值。这样,你就可以检查输入参数和选项的列表,并根据用户在命令行上的选择来执行相应的操作。\r\n\r\n你将在应用程序的主代码中使用这个 `Namespace` 对象。这与你在自定义 `ls` 命令示例中的 `for` 循环下所做的类似。\r\n\r\n到目前为止,你已经了解了创建基于 `argparse` 的 CLI 的主要步骤。现在,你可以花些时间学习如何在 Python 中组织和构建 CLI 应用程序的基础知识了。\r\n\r\n### 设置 CLI 应用程序的布局和构建系统\r\n\r\n在继续你的 `argparse` 学习之旅之前,你应该暂停一下,思考如何组织你的代码和规划一个 CLI 项目。首先,你应该考虑以下几点: \r\n\r\n- 你可以创建模块和包来组织代码。\r\n- 你可以将 Python 应用的核心包命名为应用本身的名字。\r\n- 你会根据每个 Python 模块的具体内容或功能来命名它们。\r\n- 如果你希望某个包可以直接执行,你可以在该 Python 包中添加一个 `__main__.py` 模块。\r\n\r\n将这些想法铭记于心,并考虑到模型-视图-控制器(MVC)模式是一种有效组织应用程序结构的方法,你在规划 CLI 项目时可以采用以下目录结构: \r\n```\r\nhello_cli/\r\n│\r\n├── hello_cli/\r\n│ ├── __init__.py\r\n│ ├── __main__.py\r\n│ ├── cli.py\r\n│ └── model.py\r\n│\r\n├── tests/\r\n│ ├── __init__.py\r\n│ ├── test_cli.py\r\n│ └── test_model.py\r\n│\r\n├── pyproject.toml\r\n├── README.md\r\n└── requirements.txt\r\n```\r\n\r\n`hello_cli/` 目录是项目的根目录。在那里,您将放置以下文件: \r\n\r\n- pyproject.toml 是一个 TOML 文件,用于指定项目的构建系统(build system)和其他配置(configurations)。\r\n- README.md 文件提供了项目的描述以及安装和运行应用程序的说明。为你的项目添加一个描述性且详细的 README.md 文件是编程中的最佳实践,特别是如果你打算将项目作为开源解决方案发布的话。\r\n- requirements.txt 是一个常规文件,列出了项目的外部依赖项(external dependencies)。你将使用这个文件,结合 `pip` 的 `-r` 选项,来自动安装这些依赖项。\r\n\r\n接下来是 `hello_cli/` 目录,它包含了应用的核心包,该包包含以下模块: \r\n\r\n- `__init__.py` 文件使得 `hello_cli/` 可以作为一个 Python 包被识别。\r\n- `__main__.py` 文件提供了应用程序的**入口点脚本**(entry-point script)或可执行文件,这是启动程序的主要入口。\r\n- `cli.py` 文件为应用提供了命令行界面。在此文件中的代码将扮演基于 MVC 架构中的视图-控制器角色。\r\n- `model.py` 文件包含了支持应用主要功能的代码。这部分代码将在你的 MVC 布局中扮演模型角色。\r\n\r\n你还需要一个 `tests/` 包,其中包含针对应用程序组件的单元测试文件。在这个具体的项目布局示例中,你有 `test_cli.py` 用于检查 CLI 功能的单元测试,以及 `test_model.py` 用于检查你的模型代码的单元测试。\r\n\r\n`pyproject.toml` 文件允许你定义应用程序的构建系统以及许多其他常规配置。以下是一个如何为你的示例 hello_cli 项目填写此文件的简单示例: \r\n```toml\r\n# pyproject.toml\r\n\r\n[build-system]\r\nrequires = ["setuptools>=64.0.0", "wheel"]\r\nbuild-backend = "setuptools.build_meta"\r\n\r\n[project]\r\nname = "hello_cli"\r\nversion = "0.0.1"\r\ndescription = "My awesome Hello CLI application"\r\nreadme = "README.md"\r\nauthors = [{ name = "Real Python", email = "info@realpython.com" }]\r\n\r\n[project.scripts]\r\nhello_cli = "hello_cli.__main__:main"\r\n```\r\n\r\n`[build-system]` 表头将 `setuptools` 设置为应用程序的构建系统,并指定 Python 需要安装哪些依赖项来构建应用程序。`[project]` 表头为你的应用提供了通用元数据。这些元数据在你想要将应用发布到 Python 包索引(PyPI)时非常有用。最后, `[project.scripts]` 表头定义了你的应用程序的入口点。\r\n\r\n经过这次对 CLI 项目布局和构建的快速探索,你已经准备好继续学习 `argparse` 了,特别是如何自定义你的命令行参数解析器。\r\n\r\n## 自定义你的命令行参数解析器\r\n\r\n在前面的部分中,你已经学习了如何使用 Python 的 `argparse` 模块为你的程序或应用实现命令行接口的基础知识。同时,你也了解了如何按照 MVC 模式组织和规划 CLI 应用项目。\r\n\r\n在接下来的部分中,你将更深入地探索 `argparse` 的许多其他强大功能。特别是,你将学习如何在 `ArgumentParser` 构造函数中使用一些最有用的参数,这将使你能够自定义 CLI 应用的一般行为。\r\n\r\n### 调整程序的 Help 和 Usage 内容\r\n\r\n向 CLI 应用程序的用户提供使用说明和帮助是一种最佳实践,可以通过出色的用户体验 (UX) 让用户更加愉快。在本节中,你将了解如何利用 `ArgumentParser` 的一些参数来微调 CLI 应用程序向用户显示帮助和使用消息的方式。你将学习如何: \r\n- 设置程序名称\r\n- 定义程序的描述和结束消息\r\n- 对参数和选项进行分组显示帮助\r\n\r\n首先,你将开始设置你的程序名称,并指定该名称在帮助或使用说明消息中的显示方式。\r\n\r\n#### 设置程序名称\r\n\r\n默认情况下,`argparse` 会使用 `sys.argv` 中的第一个值来设置程序的名称。这个第一项包含你刚刚执行的 Python 文件的名称。这个文件名在使用说明消息中看起来会有些奇怪。\r\n\r\n例如,继续使用 `-h` 选项运行自定义 `ls` 命令:\r\n```bash\r\n$ python ls.py -h\r\nusage: ls.py [-h] [-l] path\r\n\r\npositional arguments:\r\n path\r\n\r\noptions:\r\n -h, --help show this help message and exit\r\n -l, --long\r\n```\r\n\r\n命令输出中的高亮行显示 `argparse` 正在使用文件名 `ls.py` 作为程序的名称。这看起来有些奇怪,因为在使用说明消息中,应用名称很少包含文件扩展名。\r\n\r\n幸运的是,你可以使用 `prog` 参数来指定你的程序名称,就像下面的代码片段所示: \r\n```python\r\n# ls.py v3\r\n\r\nimport argparse\r\nimport datetime\r\nfrom pathlib import Path\r\n\r\nparser = argparse.ArgumentParser(prog="ls")\r\n\r\n# ...\r\n\r\nfor entry in target_dir.iterdir():\r\n print(build_output(entry, long=args.long))\r\n```\r\n\r\n使用 `prog` 参数,你可以指定将在使用说明消息中使用的程序名称。在这个例子中,你使用了字符串 "ls"。现在,继续运行你的应用: \r\n```bash\r\n$ python ls.py -h\r\nusage: ls [-h] [-l] path\r\n\r\npositional arguments:\r\n path\r\n\r\noptions:\r\n -h, --help show this help message and exit\r\n -l, --long\r\n```\r\n\r\n很好!这个输出的第一行中的使用说明消息显示程序名称为 `ls`,而不是 `ls.py`。\r\n\r\n除了设置程序名称外,`argparse` 还允许你定义应用的描述和结尾信息。在接下来的部分中,你将学习如何进行这两方面的操作。\r\n\r\n#### 定义程序的描述和结语消息\r\n\r\n你还可以为你的应用定义一个通用的描述和一个结尾或结束语。为此,你将分别使用 `description` 和 `epilog` 参数。接下来,请更新 `ls.py` 文件,在 `ArgumentParser` 构造函数中添加以下内容: \r\n```python\r\n# ls.py v4\r\n\r\nimport argparse\r\nimport datetime\r\nfrom pathlib import Path\r\n\r\nparser = argparse.ArgumentParser(\r\n prog="ls",\r\n description="List the content of a directory",\r\n epilog="Thanks for using %(prog)s! :)",\r\n)\r\n\r\n# ...\r\n\r\nfor entry in target_dir.iterdir():\r\n print(build_output(entry, long=args.long))\r\n```\r\n\r\n在这次更新中,`description` 参数允许你为应用提供一个通用的描述。这个描述将显示在帮助消息的开头。`epilog` 参数则允许你定义一些文本作为应用的结尾或结束语。请注意,你可以使用旧式的字符串格式化操作符(`%`)将 `prog` 参数插入到 `epilog` 字符串中。 \r\n\r\n如果再次运行该应用程序,你将得到如下输出: \r\n```bash\r\n$ python ls.py -h\r\nusage: ls [-h] [-l] path\r\n\r\nList the content of a directory\r\n\r\npositional arguments:\r\n path\r\n\r\noptions:\r\n -h, --help show this help message and exit\r\n -l, --long\r\n\r\nThanks for using ls! :)\r\n```\r\n\r\n现在,输出会在使用消息之后显示描述消息,并在帮助文本末尾显示结语消息。\r\n\r\n#### 显示参数和选项的分组帮助\r\n\r\n**帮助分组**(Help groups)是 `argparse` 的另一个有趣特性。它们允许你将相关的命令和参数进行分组,从而帮助你组织应用的帮助消息。要创建这些帮助分组,你将使用 `ArgumentParser` 的 `.add_argument_group()` 方法。\r\n\r\n作为一个例子,请考虑你自定义的 `ls` 命令的以下更新版本: \r\n```python\r\n# ls.py v5\r\n# ...\r\n\r\nparser = argparse.ArgumentParser(\r\n prog="ls",\r\n description="List the content of a directory",\r\n epilog="Thanks for using %(prog)s! :)",\r\n)\r\n\r\ngeneral = parser.add_argument_group("general output")\r\ngeneral.add_argument("path")\r\n\r\ndetailed = parser.add_argument_group("detailed output")\r\ndetailed.add_argument("-l", "--long", action="store_true")\r\n\r\nargs = parser.parse_args()\r\n\r\n# ...\r\n\r\nfor entry in target_dir.iterdir():\r\n print(build_output(entry, long=args.long))\r\n```\r\n\r\n在这次更新中,你为显示一般输出的参数和选项创建了一个帮助分组,并为显示详细输出的参数和选项创建了另一个分组。\r\n\r\n如果你在命令行中使用 `-h` 选项运行应用程序,那么你将获得以下输出: \r\n```bash\r\npython ls.py -h\r\nusage: ls [-h] [-l] path\r\n\r\nList the content of a directory\r\n\r\noptions:\r\n -h, --help show this help message and exit\r\n\r\ngeneral output:\r\n path\r\n\r\ndetailed output:\r\n -l, --long\r\n\r\nThanks for using ls! :)\r\n```\r\n\r\n现在,你的应用的参数和选项在帮助消息中以描述性的标题进行了方便的分组。这个整洁的特性将帮助你为用户提供更多的上下文,并帮助他们更好地理解应用的工作原理。\r\n\r\n### 为参数和选项提供全局设置\r\n\r\n除了自定义使用说明和帮助消息外,`ArgumentParser` 还允许你对命令行界面(CLI)应用进行其他一些有趣的调整。这些调整包括:\r\n\r\n- 为参数和选项定义全局默认值\r\n- 从外部文件中加载参数和选项\r\n- 允许或禁止选项缩写\r\n\r\n有时,你可能需要为你的应用的参数和选项指定一个全局默认值。你可以通过在调用 `ArgumentParser` 构造函数时,将默认值传递给 `argument_default` 参数来实现这一点(注意:实际上 `ArgumentParser` 没有 `argument_default` 这个参数,但这里是为了说明可以全局设置默认值的概念。在实际应用中,你可能需要为每个参数单独设置默认值)。\r\n\r\n这个特性可能并不常用,因为参数和选项通常具有不同的数据类型或意义,很难找到一个满足所有需求的值。\r\n\r\n然而,`argument_default`(尽管 `ArgumentParser` 并没有直接提供这个参数,但这里是为了说明概念)的一个常见用例是当你想要避免将参数和选项添加到 `Namespace` 对象中。在这种情况下,你可以使用 `SUPPRESS` 常量作为默认值。这个默认值将确保只有命令行中提供的参数和选项才会被存储在 `arguments` 的 `Namespace` 中。\r\n\r\n作为一个例子,请继续修改你的自定义 `ls` 命令,如下面的代码片段所示: \r\n```python\r\n# ls.py v6\r\n\r\nimport argparse\r\nimport datetime\r\nfrom pathlib import Path\r\n\r\nparser = argparse.ArgumentParser(\r\n prog="ls",\r\n description="List the content of a directory",\r\n epilog="Thanks for using %(prog)s! :)",\r\n argument_default=argparse.SUPPRESS,\r\n)\r\n\r\n# ...\r\n\r\nfor entry in target_dir.iterdir():\r\n try:\r\n long = args.long\r\n except AttributeError:\r\n long = False\r\n print(build_output(entry, long=long))\r\n```\r\n\r\n通过将 `SUPPRESS` 传递给 `ArgumentParser` 构造函数,你可以防止未提供的参数被存储在 `argparse.Namespace` 对象中。这就是为什么在调用 `build_output()` 之前,你需要检查 `-l` 或 `--long` 选项是否实际被传递了。否则,你的代码会因为 `args` 中不存在 `long` 属性而引发 `AttributeError` 错误。\r\n\r\n`ArgumentParser` 的另一个酷炫功能是允许你从外部文件中加载参数值。当你有一个具有冗长或复杂的命令行结构的应用,并希望自动化加载参数值的过程时,这个功能就非常有用。\r\n\r\n在这种情况下,你可以将参数值存储在一个外部文件中,并让你的程序从该文件中加载它们。为了尝试这个功能,请继续创建一个简单的命令行界面(CLI)应用,如下所示: \r\n```python\r\n# fromfile.py\r\n\r\nimport argparse\r\n\r\nparser = argparse.ArgumentParser(fromfile_prefix_chars="@")\r\n\r\nparser.add_argument("one")\r\nparser.add_argument("two")\r\nparser.add_argument("three")\r\n\r\nargs = parser.parse_args()\r\n\r\nprint(args)\r\n```\r\n\r\n在这里,你向 `ArgumentParser` 的 `fromfile_prefix_chars` 参数传递 `@` 符号。然后,你创建了三个必须在命令行中提供的必需参数。\r\n\r\n现在,假设你经常使用此应用程序,并且总是使用相同的一组参数值。为了简化和优化你的工作流程,你可以创建一个文件,其中包含所有必需参数的适当值,每个参数占一行,就像下面的 `args.txt` 文件一样: \r\n```\r\nfirst\r\nsecond\r\nthird\r\n```\r\n\r\n有了这个文件,您现在可以调用您的程序并指示它从 `args.txt` 文件加载值,如以下命令运行所示: \r\n```bash\r\n$ python fromfile.py @args.txt\r\nNamespace(one=\'first\', two=\'second\', three=\'third\')\r\n```\r\n\r\n在此命令的输出中,你可以看到 `argparse` 已经读取了 `args.txt` 的内容,并顺序地将值分配给了 `fromfile.py` 程序的每个参数。所有参数及其值都已成功存储在 `Namespace` 对象中。\r\n\r\n接受缩写选项名称的能力是 `argparse` 命令行界面(CLI)的另一个酷炫特性。这个特性是默认启用的,当你的程序具有长选项名称时非常有用。例如,考虑以下程序,它会在命令行下打印出你在 `--argument-with-a-long-name` 选项后指定的值: \r\n```python\r\n# abbreviate.py\r\n\r\nimport argparse\r\n\r\nparser = argparse.ArgumentParser()\r\n\r\nparser.add_argument("--argument-with-a-long-name")\r\n\r\nargs = parser.parse_args()\r\n\r\nprint(args.argument_with_a_long_name)\r\n```\r\n\r\n这个程序会打印出你在 `--argument-with-a-long-name` 选项后传入的任何参数值。现在,请继续运行以下命令来检查 Python 的 `argparse` 模块如何处理这些缩写: \r\n```bash\r\n$ python abbreviate.py --argument-with-a-long-name 42\r\n42\r\n\r\n$ python abbreviate.py --argument 42\r\n42\r\n\r\n$ python abbreviate.py --a 42\r\n42\r\n```\r\n\r\n这些示例展示了如何缩写 `--argument-with-a-long-name` 选项的名称,而应用程序仍能正常工作。此功能是默认启用的。如果你希望禁用它并禁止缩写,那么可以在 `ArgumentParser` 中使用 `allow_abbrev` 参数: \r\n```python\r\n# abbreviate.py\r\n\r\nimport argparse\r\n\r\nparser = argparse.ArgumentParser(allow_abbrev=False)\r\n\r\nparser.add_argument("--argument-with-a-long-name")\r\n\r\nargs = parser.parse_args()\r\n\r\nprint(args.argument_with_a_long_name)\r\n```\r\n\r\n将 `allow_abbrev` 设置为 `False` 会禁用命令行选项中的缩写。从这一点开始,你将需要为程序提供完整的选项名称才能正确工作。否则,你会收到一个错误: \r\n```bash\r\n$ python abbreviate.py --argument-with-a-long-name 42\r\n42\r\n\r\n$ python abbreviate.py --argument 42\r\nusage: abbreviate.py [-h] [--argument-with-a-long-name ...]\r\nabbreviate.py: error: unrecognized arguments: --argument 42\r\n```\r\n\r\n第二个示例中的错误消息告诉你 `--argument` 选项没有被识别为有效的选项。要使用该选项,你需要提供它的完整名称。\r\n\r\n## 微调你的命令行参数和选项\r\n\r\n到目前为止,你已经学习了如何定制 `ArgumentParser` 类的多个功能,以改善你的命令行界面(CLI)的用户体验。现在,你知道了如何调整你的应用程序的使用说明和帮助信息,以及如何微调命令行参数和选项的一些全局方面。\r\n\r\n在本节中,你将学习如何定制你的 CLI 的命令行参数和选项的其他几个功能。在这种情况下,你将使用 `.add_argument()` 方法及其一些最相关的参数,包括 `action`、`type`、`nargs`、`default`、`help` 等。 \r\n\r\n### 设置 Option 背后的 Action\r\n\r\n当你向命令行界面添加一个选项或标志时,通常需要定义如何将选项的值存储在调用 `.parse_args()` 后得到的 `Namespace` 对象中。为此,你会使用 `.add_argument()` 的 `action` 参数。`action` 参数的默认值为 "store",意味着提供的选项值将原样存储在 `Namespace` 中。\r\n\r\n`action` 参数可以接受几个可能的值。以下是这些可能值的列表及其含义:', 'bodyText': '原文:Build Command-Line Interfaces With Python\'s argparse\n\n命令行应用在普通用户空间中可能并不常见,但它们存在于开发、数据科学、系统管理和许多其他操作中。每个命令行应用都需要一个用户友好的命令行界面 (CLI),以便你可以与应用本身进行交互。在 Python 中,您可以使用标准库中的 argparse 模块创建功能齐全的 CLI。\n\n在本文中,你将了解如何:\n\n命令行界面入门;\n在 Python 中组织和布局命令行应用项目;\n使用 Python argparse 创建命令行界面(command-line interfaces);\n使用 argparse 一些强大的功能深度自定义您的 CLI;\n\n若要充分利用本教程,应熟悉 Python 编程,包括面向对象编程、脚本开发和执行以及 Python 包和模块等概念。如果您熟悉与使用命令行或终端相关的一般概念和主题,这也将很有帮助。\n了解命令行界面\n自从计算机发明以来,人类一直需要并找到与这些机器交互和共享信息的方法。信息交换在人、计算机软件和硬件组件之间流动。其中任意两个元素之间的共享边界通常称为接口(interface)。\n在软件开发中,接口是给定软件的特殊部分,它允许计算机系统组件之间的交互。当涉及到人机交互和软件交互时,这个重要的组件被称为用户界面(user interface)。\n您会在编程中找到不同类型的用户界面。图形用户界面 (GUI) 可能是当今最常见的。但是,您还可以找到为其用户提供命令行界面 (CLI) 的应用和程序。在本教程中,你将了解 CLI 以及如何在 Python 中创建它们。\n命令行界面 (CLI)\n命令行界面允许您通过操作系统命令行、终端或控制台与应用程序或程序进行交互。\n要了解命令行界面及其工作原理,请考虑此实际示例。假设您有一个名为 sample 包含三个示例文件的目录。如果您使用的是类 Unix 操作系统,例如 Linux 或 macOS,请继续在父目录中打开命令行窗口或终端,然后执行以下命令:\n$ ls sample/\nhello.txt lorem.md realpython.md\nUnix 的 ls 命令列出目标目录中包含的文件和子目录,该目录默认为当前工作目录。上面的命令调用没有显示有关 的内容 sample 的太多信息。它只在屏幕上显示文件名。\n假设你想要获取有关目录及其内容的更丰富信息,那么你不需要寻找其他程序,因为 ls 命令有一个功能齐全的命令行界面,并且提供了一组有用的选项,可以用来定制命令的行为。\n例如,继续执行带有 -l 选项的 ls 命令:\n$ ls -l sample/\ntotal 24\n-rw-r--r--@ 1 user staff 83 Aug 17 22:15 hello.txt\n-rw-r--r--@ 1 user staff 2609 Aug 17 22:15 lorem.md\n-rw-r--r--@ 1 user staff 428 Aug 17 22:15 realpython.md\n现在,ls 命令的输出完全不同了。该命令显示了有关 sample 目录中文件的更多信息,包括权限、所有者、组、日期和大小。它还显示了这些文件在你计算机磁盘上使用的总空间。\n这种更丰富的输出结果是由于使用了 -l 选项,这是 Unix ls 命令行界面的一部分,它启用了详细的输出格式。\n命令、参数、选项、参数和子命令\n在本教程中,您将深入了解命令(commands)及其子命令(subcommands),同时还会学习到命令行参数(command-line arguments)、选项(options)和参数(parameters)的相关知识。因此,建议您将这些术语纳入您的技术词汇库中。\n\n命令(Command):在命令行或终端窗口中运行的程序或例程。通常,您可以通过其背后的程序(underlying program)或例程(routine)的名称来识别一个命令。\n参数(Argument):命令在执行其预期操作时所需或可选的信息片段。命令通常接受一个或多个参数,您可以在命令行中以空格分隔或逗号分隔的列表形式提供这些参数。\n选项(Option),也称为 flag 或 switch:一种可选的参数,用于修改命令的行为。选项通过特定的名称(如前一个示例中的 -l)传递给命令。\n参数(Parameter):一个选项用于执行其预期操作或动作时所使用的参数。\n子命令(Subcommand)**:一个预定义的名称,可以传递给应用程序来执行特定的操作。\n\n参考上一节中的示例命令结构:\n$ ls -l sample/\n在这个例子中,您组合了命令行界面(CLI)的以下组件:\n\nls:命令的名称或应用的名称;\n-l:启用详细输出的选项(option)、开关(switch)或标志(flag);\nsample:为命令执行提供附加信息的参数(argument);\n\n现在,让我们来看下面的命令结构,它展示了 Python 包管理器 pip 的命令行界面(CLI):\n$ pip install -r requirements.txt\n这是一个常见的 pip 命令结构,您可能之前已经见过。它允许您使用 requirements.txt 文件来给指定的 Python 项目安装依赖项。在这个例子中,您使用了以下命令行界面(CLI)组件:\n\npip:命令的名称;\ninstall:pip 的子命令(subcommand)名称;\n-r:install 子命令的选项(option);\nrequirements.txt:一个参数,特别是 -r 选项的参数。\n\n现在您已经了解了命令行界面(CLI)是什么以及其主要部分或组件有哪些。接下来,是时候学习如何在 Python 中创建自己的 CLI 了。\nPython 中的 CLI 入门\nPython 附带了一些工具,这些工具可帮助您为程序和应用程序编写命令行界面(CLI)。若您需要快速为小型程序构建一个简洁的 CLI,那么可以利用 sys 模块中的 argv 属性。这个属性会自动存储您在命令行中传递给特定程序的参数。\n使用 sys.argv 构建最小的 CLI\n以使用 argv 创建最小命令行界面(CLI)为例,假设您需要编写一个小程序,该程序类似于 ls 命令,能够列出给定目录下的所有文件。在这种情况下,您可以编写如下代码:\n# ls_argv.py\n\nimport sys\nfrom pathlib import Path\n\nif (args_count := len(sys.argv)) > 2:\n print(f"One argument expected, got {args_count - 1}")\n raise SystemExit(2)\nelif args_count < 2:\n print("You must specify the target directory")\n raise SystemExit(2)\n\ntarget_dir = Path(sys.argv[1])\n\nif not target_dir.is_dir():\n print("The target directory doesn\'t exist")\n raise SystemExit(1)\n\nfor entry in target_dir.iterdir():\n print(entry.name)\n该程序通过手动处理命令行提供的参数来实现了一个简单的命令行界面(CLI),这些参数会自动存储在 sys.argv 中。sys.argv 的第一个元素始终是程序名称,第二个元素则是目标目录。由于应用程序不应接受超过一个目标目录,因此 args_count 不得超过 2。\n在检查 sys.argv 的内容后,您创建一个pathlib.Path对象来存储目标目录的路径。如果该目录不存在,您将通知用户并退出程序。接下来的for循环将列出目录内容,每行一个条目。\n如果从命令行运行该脚本,您将得到以下结果:\n$ python ls_argv.py sample/\nhello.txt\nlorem.md\nrealpython.md\n\n$ python ls_argv.py\nYou must specify the target directory\n\n$ python ls_argv.py sample/ other_dir/\nOne argument expected, got 2\n\n$ python ls_argv.py non_existing/\nThe target directory doesn\'t exist\n您的程序接受一个目录作为参数,并列出其内容。如果您运行命令时没有提供参数,您将收到一个错误消息。如果您运行命令时指定了超过一个目标目录,您同样会收到一个错误消息。如果尝试运行命令并指定一个不存在的目录,程序将输出另一个错误消息。\n虽然您的程序运行正常,但对于更复杂的 CLI 应用程序来说,使用sys.argv属性手动解析命令行参数并不是一个可扩展的解决方案。如果您的应用需要接受更多的参数和选项,那么解析sys.argv将变得复杂且容易出错。您需要一个更好的解决方案,这就是 Python 中的argparse模块所提供的。\n使用 argparse 创建 CLI\n在 Python 中创建 CLI 应用程序的更便捷方法是使用标准库中的 argparse 模块。该模块首次在 Python 3.2 中随 PEP-389 一同发布,是快速创建 Python CLI 应用程序的利器,无需安装如 Typer 或 Click 这样的第三方库。\nargparse 模块是作为较旧的 getopt 和 optparse 模块的替代品而发布的,因为它们缺乏一些重要的功能。\nPython 的 argparse 模块允许您:\n\n解析命令行参数(arguments)和选项(options);\n在一个单一选项中接受可变数量的参数(variable number of parameters);\n在 CLI 中提供子命令(subcommands)。\n\n这些特性使 argparse 成为了一个强大的 CLI 框架,您在创建 CLI 应用程序时可以放心地依赖它。要使用 Python 的 argparse,您需要遵循以下四个简单的步骤:\n\n导入 argparse;\n通过实例化 ArgumentParser 创建参数解析器(argument parser);\n使用 .add_argument() 方法向解析器添加参数(arguments)和选项(options);\n在解析器上调用 .parse_args() 以获取参数 Namespace。\n\n例如,您可以使用 argparse 来改进您的 ls_argv.py 脚本。现在,您可以创建一个名为 ls.py 的脚本,并编写以下代码:\n# ls.py v1\n\nimport argparse\nfrom pathlib import Path\n\nparser = argparse.ArgumentParser()\n\nparser.add_argument("path")\n\nargs = parser.parse_args()\n\ntarget_dir = Path(args.path)\n\nif not target_dir.exists():\n print("The target directory doesn\'t exist")\n raise SystemExit(1)\n\nfor entry in target_dir.iterdir():\n print(entry.name)\n随着 argparse 的引入,您的代码发生了显著的变化。与之前的版本相比,最明显的不同是,用于检查用户提供的参数的条件语句已经消失了。这是因为 argparse 会自动为您检查参数的存在性。\n在这个新的实现中,您首先导入 argparse 并创建一个参数解析器。要创建解析器,您可以使用 ArgumentParser 类。接下来,您定义一个名为 path 的参数,用于获取用户的目标目录。\n接下来,您需要调用 .parse_args() 方法来解析输入参数,并获取一个包含所有用户参数的 Namespace 对象。请注意,现在 args 变量保存了一个 Namespace 对象,该对象具有从命令行收集的每个参数所对应的属性。\n在这个例子中,您只有一个参数,名为 path。Namespace 对象允许您使用点表示法通过 args 来访问 path。其余的代码与第一个实现相同。\n现在继续从命令行运行这个新脚本:\n$ python ls.py sample/\nlorem.md\nrealpython.md\nhello.txt\n\n$ python ls.py\nusage: ls.py [-h] path\nls.py: error: the following arguments are required: path\n\n$ python ls.py sample/ other_dir/\nusage: ls.py [-h] path\nls.py: error: unrecognized arguments: other_dir/\n\n$ python ls.py non_existing/\nThe target directory doesn\'t exist\n第一个命令的输出与您的原始脚本 ls_argv.py 相同。而第二个命令的输出则与 ls_argv.py 中的输出大不相同。程序现在会显示一个使用说明消息,并发出错误提示,告诉您必须提供 path 参数。\n在第三个命令中,您传递了两个目标目录,但应用程序并未为此做好准备。因此,它再次显示使用说明消息,并抛出一个错误,告知您潜在的问题。\n最后,如果您运行脚本时传递了一个不存在的目录作为参数,那么您会收到一个错误,告知您目标目录不存在,因此程序无法执行其工作。\n现在,您可以使用一个新的隐式特性。现在,您的程序接受一个可选的 -h 标志。不妨尝试一下:\n$ python ls.py -h\nusage: ls.py [-h] path\n\npositional arguments:\n path\n\noptions:\n -h, --help show this help message and exit\n太棒了,现在您的程序会自动响应 -h 或 --help 标志,并为您显示带有使用说明的帮助消息。这真是一个很棒的特性,而且您只需在代码中引入 argparse 就能轻松获得!\n经过这个快速介绍如何在 Python 中创建 CLI 应用后,您现在就可以深入研究 argparse 模块及其所有炫酷特性了。\n使用 Python 的 argparse 创建 CLI\n您可以使用 argparse 模块为您的应用程序和项目编写用户友好的命令行界面。该模块允许您定义应用程序所需的参数和选项。然后,argparse 将负责为您解析 sys.argv 的参数和选项。\nargparse 的另一个酷炫特性是它可以自动为您的 CLI 应用程序生成使用说明和帮助消息。该模块还会在参数无效时发出错误提示,并具备更多功能。\n在深入研究 argparse 之前,您需要知道该模块的文档可识别两种不同类型的命令行参数:\n\n位置参数(Positional arguments),您称为参数(arguments);\n可选参数(Optional arguments),即选项(options)、标志(flags)或开关(switches)。\n\n在 ls.py 的示例中,path 是一个位置参数(positional argument)。这样的参数之所以被称为位置参数,是因为它在命令构造中的相对位置定义了其作用。\n与位置参数不同,可选参数(Optional arguments)并不是必需的。它们允许你修改命令的行为。以 Unix 命令 ls 为例,-l 标志就是一个可选参数,它使得命令以详细模式显示输出。\n在明确了这些概念之后,你就可以着手使用 Python 和 argparse 库来构建自己的命令行界面(CLI)应用程序了。\n创建命令行参数解析器\n命令行参数解析器是任何使用 argparse 的命令行界面(CLI)中最为关键的部分。你在命令行上提供的所有参数和选项都会经过这个解析器的处理,它会为你完成繁重的解析工作。\n要使用 argparse 创建命令行参数解析器,您需要实例化 ArgumentParser 类:\n>>> from argparse import ArgumentParser\n\n>>> parser = ArgumentParser()\n>>> parser\nArgumentParser(\n prog=\'\',\n usage=None,\n description=None,\n formatter_class=,\n conflict_handler=\'error\',\n add_help=True\n)\nArgumentParser 的构造函数接受多种不同的参数,你可以利用这些参数来微调你的 CLI 的多个特性。由于所有这些参数都是可选的,因此你可以通过不传入任何参数直接实例化 ArgumentParser 来创建一个最基本的解析器。\n在本教程中,你将会更深入地了解 ArgumentParser 构造函数的参数,特别是在定制你的参数解析器的部分。目前,你可以开始使用 argparse 创建 CLI 的下一步了。这一步就是通过解析器对象来添加参数和选项。\n添加参数和选项\n要为 argparse 的 CLI 添加参数和选项,你将使用 ArgumentParser 实例的 .add_argument() 方法。请注意,这个方法对参数和选项都是通用的。在 argparse 的术语中,参数被称为位置参数(positional arguments),而选项被称为可选参数(optional arguments)。\n.add_argument() 方法的第一个参数决定了参数和选项之间的区别。这个参数被标识为名称(name)或标志(flag)。因此,如果你提供一个 name,那么你将定义一个参数(argument)。相反,如果你使用一个 flag,那么你将添加一个选项(option)。\n你已经在使用 argparse 时处理过命令行参数了。现在,考虑以下你自定义的 ls 命令的增强版本,它向 CLI 添加了一个 -l 选项:\n# ls.py v2\n\nimport argparse\nimport datetime\nfrom pathlib import Path\n\nparser = argparse.ArgumentParser()\n\nparser.add_argument("path")\n\nparser.add_argument("-l", "--long", action="store_true")\n\nargs = parser.parse_args()\n\ntarget_dir = Path(args.path)\n\nif not target_dir.exists():\n print("The target directory doesn\'t exist")\n raise SystemExit(1)\n\ndef build_output(entry, long=False):\n if long:\n size = entry.stat().st_size\n date = datetime.datetime.fromtimestamp(\n entry.stat().st_mtime).strftime(\n "%b %d %H:%M:%S"\n )\n return f"{size:>6d} {date} {entry.name}"\n return entry.name\n\nfor entry in target_dir.iterdir():\n print(build_output(entry, long=args.long))\n在这个例子中,第 11 行代码创建了一个带有 -l 和 --long 标志的选项。参数(arguments)和选项(options)在语法上的区别在于,选项名称以短横线 - 开头表示简写标志,以双短横线 -- 开头表示完整标志。\n请注意,在这个特定例子中,与 -l 或 --long 选项一同设置了一个 action 参数为 "store_true",这意味着这个选项将存储一个布尔值。如果你在命令行上提供了这个选项,那么它的值将为 True。如果你省略了这个选项,那么它的值将为 False。在 "设置 Option 背后的 Action" 部分内容中,你将了解更多关于 .add_argument() 中的 action 参数的信息。\n在第 21 行的 build_output() 函数中,当 long 为 True 时,它会返回一个详细的输出,否则返回一个简短的输出。详细的输出将包含目标目录中所有条目的大小、修改日期和名称。它使用了诸如 Path.stat() 这样的工具,以及带有自定义字符串格式的 datetime.datetime 对象。\n继续在 sample 上执行您的程序,以检查 -l 选项如何工作:\n$ python ls.py -l sample/\n 2609 Oct 28 14:07:04 lorem.md\n 428 Oct 28 14:07:04 realpython.md\n 83 Oct 28 14:07:04 hello.txt\n新增的 -l 选项允许你生成并显示关于目标目录内容的更详细输出。\n既然你已经知道了如何向 CLI 添加命令行参数和选项,接下来就是深入解析这些参数和选项的时候了。这将是你在接下来部分要探索的内容。\n解析命令行参数和选项\n解析命令行参数是基于 argparse 的任何 CLI 应用中的另一个重要步骤。一旦你解析了参数,你就可以根据它们的值来执行相应的操作。在你自定义的 ls 命令示例中,参数解析发生在包含 args = parser.parse_args() 语句的行上。\n这个语句调用了 .parse_args() 方法,并将其返回值赋给 args 变量。.parse_args() 的返回值是一个 Namespace 对象,其中包含了在命令行上提供的所有参数和选项以及它们对应的值。\n考虑以下简单的示例:\n>>> from argparse import ArgumentParser\n\n>>> parser = ArgumentParser()\n\n>>> parser.add_argument("site")\n_StoreAction(...)\n\n>>> parser.add_argument("-c", "--connect", action="store_true")\n_StoreTrueAction(...)\n\n>>> args = parser.parse_args(["Real Python", "-c"])\n>>> args\nNamespace(site=\'Real Python\', connect=True)\n\n>>> args.site\n\'Real Python\'\n>>> args.connect\nTrue\n通过在命令行参数解析器上调用 .parse_args() 方法得到的 Namespace 对象,你可以使用点表示法(dot notation)访问所有输入参数、选项以及它们对应的值。这样,你就可以检查输入参数和选项的列表,并根据用户在命令行上的选择来执行相应的操作。\n你将在应用程序的主代码中使用这个 Namespace 对象。这与你在自定义 ls 命令示例中的 for 循环下所做的类似。\n到目前为止,你已经了解了创建基于 argparse 的 CLI 的主要步骤。现在,你可以花些时间学习如何在 Python 中组织和构建 CLI 应用程序的基础知识了。\n设置 CLI 应用程序的布局和构建系统\n在继续你的 argparse 学习之旅之前,你应该暂停一下,思考如何组织你的代码和规划一个 CLI 项目。首先,你应该考虑以下几点:\n\n你可以创建模块和包来组织代码。\n你可以将 Python 应用的核心包命名为应用本身的名字。\n你会根据每个 Python 模块的具体内容或功能来命名它们。\n如果你希望某个包可以直接执行,你可以在该 Python 包中添加一个 __main__.py 模块。\n\n将这些想法铭记于心,并考虑到模型-视图-控制器(MVC)模式是一种有效组织应用程序结构的方法,你在规划 CLI 项目时可以采用以下目录结构:\nhello_cli/\n│\n├── hello_cli/\n│ ├── __init__.py\n│ ├── __main__.py\n│ ├── cli.py\n│ └── model.py\n│\n├── tests/\n│ ├── __init__.py\n│ ├── test_cli.py\n│ └── test_model.py\n│\n├── pyproject.toml\n├── README.md\n└── requirements.txt\n\nhello_cli/ 目录是项目的根目录。在那里,您将放置以下文件:\n\npyproject.toml 是一个 TOML 文件,用于指定项目的构建系统(build system)和其他配置(configurations)。\nREADME.md 文件提供了项目的描述以及安装和运行应用程序的说明。为你的项目添加一个描述性且详细的 README.md 文件是编程中的最佳实践,特别是如果你打算将项目作为开源解决方案发布的话。\nrequirements.txt 是一个常规文件,列出了项目的外部依赖项(external dependencies)。你将使用这个文件,结合 pip 的 -r 选项,来自动安装这些依赖项。\n\n接下来是 hello_cli/ 目录,它包含了应用的核心包,该包包含以下模块:\n\n__init__.py 文件使得 hello_cli/ 可以作为一个 Python 包被识别。\n__main__.py 文件提供了应用程序的入口点脚本(entry-point script)或可执行文件,这是启动程序的主要入口。\ncli.py 文件为应用提供了命令行界面。在此文件中的代码将扮演基于 MVC 架构中的视图-控制器角色。\nmodel.py 文件包含了支持应用主要功能的代码。这部分代码将在你的 MVC 布局中扮演模型角色。\n\n你还需要一个 tests/ 包,其中包含针对应用程序组件的单元测试文件。在这个具体的项目布局示例中,你有 test_cli.py 用于检查 CLI 功能的单元测试,以及 test_model.py 用于检查你的模型代码的单元测试。\npyproject.toml 文件允许你定义应用程序的构建系统以及许多其他常规配置。以下是一个如何为你的示例 hello_cli 项目填写此文件的简单示例:\n# pyproject.toml\n\n[build-system]\nrequires = ["setuptools>=64.0.0", "wheel"]\nbuild-backend = "setuptools.build_meta"\n\n[project]\nname = "hello_cli"\nversion = "0.0.1"\ndescription = "My awesome Hello CLI application"\nreadme = "README.md"\nauthors = [{ name = "Real Python", email = "info@realpython.com" }]\n\n[project.scripts]\nhello_cli = "hello_cli.__main__:main"\n[build-system] 表头将 setuptools 设置为应用程序的构建系统,并指定 Python 需要安装哪些依赖项来构建应用程序。[project] 表头为你的应用提供了通用元数据。这些元数据在你想要将应用发布到 Python 包索引(PyPI)时非常有用。最后, [project.scripts] 表头定义了你的应用程序的入口点。\n经过这次对 CLI 项目布局和构建的快速探索,你已经准备好继续学习 argparse 了,特别是如何自定义你的命令行参数解析器。\n自定义你的命令行参数解析器\n在前面的部分中,你已经学习了如何使用 Python 的 argparse 模块为你的程序或应用实现命令行接口的基础知识。同时,你也了解了如何按照 MVC 模式组织和规划 CLI 应用项目。\n在接下来的部分中,你将更深入地探索 argparse 的许多其他强大功能。特别是,你将学习如何在 ArgumentParser 构造函数中使用一些最有用的参数,这将使你能够自定义 CLI 应用的一般行为。\n调整程序的 Help 和 Usage 内容\n向 CLI 应用程序的用户提供使用说明和帮助是一种最佳实践,可以通过出色的用户体验 (UX) 让用户更加愉快。在本节中,你将了解如何利用 ArgumentParser 的一些参数来微调 CLI 应用程序向用户显示帮助和使用消息的方式。你将学习如何:\n\n设置程序名称\n定义程序的描述和结束消息\n对参数和选项进行分组显示帮助\n\n首先,你将开始设置你的程序名称,并指定该名称在帮助或使用说明消息中的显示方式。\n设置程序名称\n默认情况下,argparse 会使用 sys.argv 中的第一个值来设置程序的名称。这个第一项包含你刚刚执行的 Python 文件的名称。这个文件名在使用说明消息中看起来会有些奇怪。\n例如,继续使用 -h 选项运行自定义 ls 命令:\n$ python ls.py -h\nusage: ls.py [-h] [-l] path\n\npositional arguments:\n path\n\noptions:\n -h, --help show this help message and exit\n -l, --long\n命令输出中的高亮行显示 argparse 正在使用文件名 ls.py 作为程序的名称。这看起来有些奇怪,因为在使用说明消息中,应用名称很少包含文件扩展名。\n幸运的是,你可以使用 prog 参数来指定你的程序名称,就像下面的代码片段所示:\n# ls.py v3\n\nimport argparse\nimport datetime\nfrom pathlib import Path\n\nparser = argparse.ArgumentParser(prog="ls")\n\n# ...\n\nfor entry in target_dir.iterdir():\n print(build_output(entry, long=args.long))\n使用 prog 参数,你可以指定将在使用说明消息中使用的程序名称。在这个例子中,你使用了字符串 "ls"。现在,继续运行你的应用:\n$ python ls.py -h\nusage: ls [-h] [-l] path\n\npositional arguments:\n path\n\noptions:\n -h, --help show this help message and exit\n -l, --long\n很好!这个输出的第一行中的使用说明消息显示程序名称为 ls,而不是 ls.py。\n除了设置程序名称外,argparse 还允许你定义应用的描述和结尾信息。在接下来的部分中,你将学习如何进行这两方面的操作。\n定义程序的描述和结语消息\n你还可以为你的应用定义一个通用的描述和一个结尾或结束语。为此,你将分别使用 description 和 epilog 参数。接下来,请更新 ls.py 文件,在 ArgumentParser 构造函数中添加以下内容:\n# ls.py v4\n\nimport argparse\nimport datetime\nfrom pathlib import Path\n\nparser = argparse.ArgumentParser(\n prog="ls",\n description="List the content of a directory",\n epilog="Thanks for using %(prog)s! :)",\n)\n\n# ...\n\nfor entry in target_dir.iterdir():\n print(build_output(entry, long=args.long))\n在这次更新中,description 参数允许你为应用提供一个通用的描述。这个描述将显示在帮助消息的开头。epilog 参数则允许你定义一些文本作为应用的结尾或结束语。请注意,你可以使用旧式的字符串格式化操作符(%)将 prog 参数插入到 epilog 字符串中。\n如果再次运行该应用程序,你将得到如下输出:\n$ python ls.py -h\nusage: ls [-h] [-l] path\n\nList the content of a directory\n\npositional arguments:\n path\n\noptions:\n -h, --help show this help message and exit\n -l, --long\n\nThanks for using ls! :)\n现在,输出会在使用消息之后显示描述消息,并在帮助文本末尾显示结语消息。\n显示参数和选项的分组帮助\n帮助分组(Help groups)是 argparse 的另一个有趣特性。它们允许你将相关的命令和参数进行分组,从而帮助你组织应用的帮助消息。要创建这些帮助分组,你将使用 ArgumentParser 的 .add_argument_group() 方法。\n作为一个例子,请考虑你自定义的 ls 命令的以下更新版本:\n# ls.py v5\n# ...\n\nparser = argparse.ArgumentParser(\n prog="ls",\n description="List the content of a directory",\n epilog="Thanks for using %(prog)s! :)",\n)\n\ngeneral = parser.add_argument_group("general output")\ngeneral.add_argument("path")\n\ndetailed = parser.add_argument_group("detailed output")\ndetailed.add_argument("-l", "--long", action="store_true")\n\nargs = parser.parse_args()\n\n# ...\n\nfor entry in target_dir.iterdir():\n print(build_output(entry, long=args.long))\n在这次更新中,你为显示一般输出的参数和选项创建了一个帮助分组,并为显示详细输出的参数和选项创建了另一个分组。\n如果你在命令行中使用 -h 选项运行应用程序,那么你将获得以下输出:\npython ls.py -h\nusage: ls [-h] [-l] path\n\nList the content of a directory\n\noptions:\n -h, --help show this help message and exit\n\ngeneral output:\n path\n\ndetailed output:\n -l, --long\n\nThanks for using ls! :)\n现在,你的应用的参数和选项在帮助消息中以描述性的标题进行了方便的分组。这个整洁的特性将帮助你为用户提供更多的上下文,并帮助他们更好地理解应用的工作原理。\n为参数和选项提供全局设置\n除了自定义使用说明和帮助消息外,ArgumentParser 还允许你对命令行界面(CLI)应用进行其他一些有趣的调整。这些调整包括:\n\n为参数和选项定义全局默认值\n从外部文件中加载参数和选项\n允许或禁止选项缩写\n\n有时,你可能需要为你的应用的参数和选项指定一个全局默认值。你可以通过在调用 ArgumentParser 构造函数时,将默认值传递给 argument_default 参数来实现这一点(注意:实际上 ArgumentParser 没有 argument_default 这个参数,但这里是为了说明可以全局设置默认值的概念。在实际应用中,你可能需要为每个参数单独设置默认值)。\n这个特性可能并不常用,因为参数和选项通常具有不同的数据类型或意义,很难找到一个满足所有需求的值。\n然而,argument_default(尽管 ArgumentParser 并没有直接提供这个参数,但这里是为了说明概念)的一个常见用例是当你想要避免将参数和选项添加到 Namespace 对象中。在这种情况下,你可以使用 SUPPRESS 常量作为默认值。这个默认值将确保只有命令行中提供的参数和选项才会被存储在 arguments 的 Namespace 中。\n作为一个例子,请继续修改你的自定义 ls 命令,如下面的代码片段所示:\n# ls.py v6\n\nimport argparse\nimport datetime\nfrom pathlib import Path\n\nparser = argparse.ArgumentParser(\n prog="ls",\n description="List the content of a directory",\n epilog="Thanks for using %(prog)s! :)",\n argument_default=argparse.SUPPRESS,\n)\n\n# ...\n\nfor entry in target_dir.iterdir():\n try:\n long = args.long\n except AttributeError:\n long = False\n print(build_output(entry, long=long))\n通过将 SUPPRESS 传递给 ArgumentParser 构造函数,你可以防止未提供的参数被存储在 argparse.Namespace 对象中。这就是为什么在调用 build_output() 之前,你需要检查 -l 或 --long 选项是否实际被传递了。否则,你的代码会因为 args 中不存在 long 属性而引发 AttributeError 错误。\nArgumentParser 的另一个酷炫功能是允许你从外部文件中加载参数值。当你有一个具有冗长或复杂的命令行结构的应用,并希望自动化加载参数值的过程时,这个功能就非常有用。\n在这种情况下,你可以将参数值存储在一个外部文件中,并让你的程序从该文件中加载它们。为了尝试这个功能,请继续创建一个简单的命令行界面(CLI)应用,如下所示:\n# fromfile.py\n\nimport argparse\n\nparser = argparse.ArgumentParser(fromfile_prefix_chars="@")\n\nparser.add_argument("one")\nparser.add_argument("two")\nparser.add_argument("three")\n\nargs = parser.parse_args()\n\nprint(args)\n在这里,你向 ArgumentParser 的 fromfile_prefix_chars 参数传递 @ 符号。然后,你创建了三个必须在命令行中提供的必需参数。\n现在,假设你经常使用此应用程序,并且总是使用相同的一组参数值。为了简化和优化你的工作流程,你可以创建一个文件,其中包含所有必需参数的适当值,每个参数占一行,就像下面的 args.txt 文件一样:\nfirst\nsecond\nthird\n\n有了这个文件,您现在可以调用您的程序并指示它从 args.txt 文件加载值,如以下命令运行所示:\n$ python fromfile.py @args.txt\nNamespace(one=\'first\', two=\'second\', three=\'third\')\n在此命令的输出中,你可以看到 argparse 已经读取了 args.txt 的内容,并顺序地将值分配给了 fromfile.py 程序的每个参数。所有参数及其值都已成功存储在 Namespace 对象中。\n接受缩写选项名称的能力是 argparse 命令行界面(CLI)的另一个酷炫特性。这个特性是默认启用的,当你的程序具有长选项名称时非常有用。例如,考虑以下程序,它会在命令行下打印出你在 --argument-with-a-long-name 选项后指定的值:\n# abbreviate.py\n\nimport argparse\n\nparser = argparse.ArgumentParser()\n\nparser.add_argument("--argument-with-a-long-name")\n\nargs = parser.parse_args()\n\nprint(args.argument_with_a_long_name)\n这个程序会打印出你在 --argument-with-a-long-name 选项后传入的任何参数值。现在,请继续运行以下命令来检查 Python 的 argparse 模块如何处理这些缩写:\n$ python abbreviate.py --argument-with-a-long-name 42\n42\n\n$ python abbreviate.py --argument 42\n42\n\n$ python abbreviate.py --a 42\n42\n这些示例展示了如何缩写 --argument-with-a-long-name 选项的名称,而应用程序仍能正常工作。此功能是默认启用的。如果你希望禁用它并禁止缩写,那么可以在 ArgumentParser 中使用 allow_abbrev 参数:\n# abbreviate.py\n\nimport argparse\n\nparser = argparse.ArgumentParser(allow_abbrev=False)\n\nparser.add_argument("--argument-with-a-long-name")\n\nargs = parser.parse_args()\n\nprint(args.argument_with_a_long_name)\n将 allow_abbrev 设置为 False 会禁用命令行选项中的缩写。从这一点开始,你将需要为程序提供完整的选项名称才能正确工作。否则,你会收到一个错误:\n$ python abbreviate.py --argument-with-a-long-name 42\n42\n\n$ python abbreviate.py --argument 42\nusage: abbreviate.py [-h] [--argument-with-a-long-name ...]\nabbreviate.py: error: unrecognized arguments: --argument 42\n第二个示例中的错误消息告诉你 --argument 选项没有被识别为有效的选项。要使用该选项,你需要提供它的完整名称。\n微调你的命令行参数和选项\n到目前为止,你已经学习了如何定制 ArgumentParser 类的多个功能,以改善你的命令行界面(CLI)的用户体验。现在,你知道了如何调整你的应用程序的使用说明和帮助信息,以及如何微调命令行参数和选项的一些全局方面。\n在本节中,你将学习如何定制你的 CLI 的命令行参数和选项的其他几个功能。在这种情况下,你将使用 .add_argument() 方法及其一些最相关的参数,包括 action、type、nargs、default、help 等。\n设置 Option 背后的 Action\n当你向命令行界面添加一个选项或标志时,通常需要定义如何将选项的值存储在调用 .parse_args() 后得到的 Namespace 对象中。为此,你会使用 .add_argument() 的 action 参数。action 参数的默认值为 "store",意味着提供的选项值将原样存储在 Namespace 中。\naction 参数可以接受几个可能的值。以下是这些可能值的列表及其含义:', 'bodyHTML': '
\n

原文:Build Command-Line Interfaces With Python\'s argparse

\n
\n

命令行应用在普通用户空间中可能并不常见,但它们存在于开发、数据科学、系统管理和许多其他操作中。每个命令行应用都需要一个用户友好的命令行界面 (CLI),以便你可以与应用本身进行交互。在 Python 中,您可以使用标准库中的 argparse 模块创建功能齐全的 CLI。

\n\n

在本文中,你将了解如何:

\n
    \n
  • 命令行界面入门;
  • \n
  • 在 Python 中组织和布局命令行应用项目;
  • \n
  • 使用 Python argparse 创建命令行界面(command-line interfaces);
  • \n
  • 使用 argparse 一些强大的功能深度自定义您的 CLI;
  • \n
\n

若要充分利用本教程,应熟悉 Python 编程,包括面向对象编程、脚本开发和执行以及 Python 包和模块等概念。如果您熟悉与使用命令行或终端相关的一般概念和主题,这也将很有帮助。

\n

了解命令行界面

\n

自从计算机发明以来,人类一直需要并找到与这些机器交互和共享信息的方法。信息交换在人、计算机软件和硬件组件之间流动。其中任意两个元素之间的共享边界通常称为接口(interface)。

\n

在软件开发中,接口是给定软件的特殊部分,它允许计算机系统组件之间的交互。当涉及到人机交互和软件交互时,这个重要的组件被称为用户界面(user interface)。

\n

您会在编程中找到不同类型的用户界面。图形用户界面 (GUI) 可能是当今最常见的。但是,您还可以找到为其用户提供命令行界面 (CLI) 的应用和程序。在本教程中,你将了解 CLI 以及如何在 Python 中创建它们。

\n

命令行界面 (CLI)

\n

命令行界面允许您通过操作系统命令行、终端或控制台与应用程序或程序进行交互。

\n

要了解命令行界面及其工作原理,请考虑此实际示例。假设您有一个名为 sample 包含三个示例文件的目录。如果您使用的是类 Unix 操作系统,例如 Linux 或 macOS,请继续在父目录中打开命令行窗口或终端,然后执行以下命令:

\n
$ ls sample/\nhello.txt     lorem.md      realpython.md
\n

Unix 的 ls 命令列出目标目录中包含的文件和子目录,该目录默认为当前工作目录。上面的命令调用没有显示有关 的内容 sample 的太多信息。它只在屏幕上显示文件名。

\n

假设你想要获取有关目录及其内容的更丰富信息,那么你不需要寻找其他程序,因为 ls 命令有一个功能齐全的命令行界面,并且提供了一组有用的选项,可以用来定制命令的行为。

\n

例如,继续执行带有 -l 选项的 ls 命令:

\n
$ ls -l sample/\ntotal 24\n-rw-r--r--@ 1 user  staff    83 Aug 17 22:15 hello.txt\n-rw-r--r--@ 1 user  staff  2609 Aug 17 22:15 lorem.md\n-rw-r--r--@ 1 user  staff   428 Aug 17 22:15 realpython.md
\n

现在,ls 命令的输出完全不同了。该命令显示了有关 sample 目录中文件的更多信息,包括权限、所有者、组、日期和大小。它还显示了这些文件在你计算机磁盘上使用的总空间。

\n

这种更丰富的输出结果是由于使用了 -l 选项,这是 Unix ls 命令行界面的一部分,它启用了详细的输出格式。

\n

命令、参数、选项、参数和子命令

\n

在本教程中,您将深入了解命令(commands)及其子命令(subcommands),同时还会学习到命令行参数(command-line arguments)、选项(options)和参数(parameters)的相关知识。因此,建议您将这些术语纳入您的技术词汇库中。

\n
    \n
  • 命令(Command):在命令行或终端窗口中运行的程序或例程。通常,您可以通过其背后的程序(underlying program)或例程(routine)的名称来识别一个命令。
  • \n
  • 参数(Argument):命令在执行其预期操作时所需或可选的信息片段。命令通常接受一个或多个参数,您可以在命令行中以空格分隔或逗号分隔的列表形式提供这些参数。
  • \n
  • 选项(Option),也称为 flagswitch:一种可选的参数,用于修改命令的行为。选项通过特定的名称(如前一个示例中的 -l)传递给命令。
  • \n
  • 参数(Parameter):一个选项用于执行其预期操作或动作时所使用的参数。
  • \n
  • 子命令(Subcommand)**:一个预定义的名称,可以传递给应用程序来执行特定的操作。
  • \n
\n

参考上一节中的示例命令结构:

\n
$ ls -l sample/
\n

在这个例子中,您组合了命令行界面(CLI)的以下组件:

\n
    \n
  • ls:命令的名称或应用的名称;
  • \n
  • -l:启用详细输出的选项(option)、开关(switch)或标志(flag);
  • \n
  • sample:为命令执行提供附加信息的参数(argument);
  • \n
\n

现在,让我们来看下面的命令结构,它展示了 Python 包管理器 pip 的命令行界面(CLI):

\n
$ pip install -r requirements.txt
\n

这是一个常见的 pip 命令结构,您可能之前已经见过。它允许您使用 requirements.txt 文件来给指定的 Python 项目安装依赖项。在这个例子中,您使用了以下命令行界面(CLI)组件:

\n
    \n
  • pip:命令的名称;
  • \n
  • installpip 的子命令(subcommand)名称;
  • \n
  • -rinstall 子命令的选项(option);
  • \n
  • requirements.txt:一个参数,特别是 -r 选项的参数。
  • \n
\n

现在您已经了解了命令行界面(CLI)是什么以及其主要部分或组件有哪些。接下来,是时候学习如何在 Python 中创建自己的 CLI 了。

\n

Python 中的 CLI 入门

\n

Python 附带了一些工具,这些工具可帮助您为程序和应用程序编写命令行界面(CLI)。若您需要快速为小型程序构建一个简洁的 CLI,那么可以利用 sys 模块中的 argv 属性。这个属性会自动存储您在命令行中传递给特定程序的参数。

\n

使用 sys.argv 构建最小的 CLI

\n

以使用 argv 创建最小命令行界面(CLI)为例,假设您需要编写一个小程序,该程序类似于 ls 命令,能够列出给定目录下的所有文件。在这种情况下,您可以编写如下代码:

\n
# ls_argv.py\n\nimport sys\nfrom pathlib import Path\n\nif (args_count := len(sys.argv)) > 2:\n    print(f"One argument expected, got {args_count - 1}")\n    raise SystemExit(2)\nelif args_count < 2:\n    print("You must specify the target directory")\n    raise SystemExit(2)\n\ntarget_dir = Path(sys.argv[1])\n\nif not target_dir.is_dir():\n    print("The target directory doesn\'t exist")\n    raise SystemExit(1)\n\nfor entry in target_dir.iterdir():\n    print(entry.name)
\n

该程序通过手动处理命令行提供的参数来实现了一个简单的命令行界面(CLI),这些参数会自动存储在 sys.argv 中。sys.argv 的第一个元素始终是程序名称,第二个元素则是目标目录。由于应用程序不应接受超过一个目标目录,因此 args_count 不得超过 2。

\n

在检查 sys.argv 的内容后,您创建一个pathlib.Path对象来存储目标目录的路径。如果该目录不存在,您将通知用户并退出程序。接下来的for循环将列出目录内容,每行一个条目。

\n

如果从命令行运行该脚本,您将得到以下结果:

\n
$ python ls_argv.py sample/\nhello.txt\nlorem.md\nrealpython.md\n\n$ python ls_argv.py\nYou must specify the target directory\n\n$ python ls_argv.py sample/ other_dir/\nOne argument expected, got 2\n\n$ python ls_argv.py non_existing/\nThe target directory doesn\'t exist
\n

您的程序接受一个目录作为参数,并列出其内容。如果您运行命令时没有提供参数,您将收到一个错误消息。如果您运行命令时指定了超过一个目标目录,您同样会收到一个错误消息。如果尝试运行命令并指定一个不存在的目录,程序将输出另一个错误消息。

\n

虽然您的程序运行正常,但对于更复杂的 CLI 应用程序来说,使用sys.argv属性手动解析命令行参数并不是一个可扩展的解决方案。如果您的应用需要接受更多的参数和选项,那么解析sys.argv将变得复杂且容易出错。您需要一个更好的解决方案,这就是 Python 中的argparse模块所提供的。

\n

使用 argparse 创建 CLI

\n

在 Python 中创建 CLI 应用程序的更便捷方法是使用标准库中的 argparse 模块。该模块首次在 Python 3.2 中随 PEP-389 一同发布,是快速创建 Python CLI 应用程序的利器,无需安装如 Typer 或 Click 这样的第三方库。

\n

argparse 模块是作为较旧的 getoptoptparse 模块的替代品而发布的,因为它们缺乏一些重要的功能。

\n

Python 的 argparse 模块允许您:

\n
    \n
  • 解析命令行参数(arguments)和选项(options);
  • \n
  • 在一个单一选项中接受可变数量的参数(variable number of parameters);
  • \n
  • 在 CLI 中提供子命令(subcommands)。
  • \n
\n

这些特性使 argparse 成为了一个强大的 CLI 框架,您在创建 CLI 应用程序时可以放心地依赖它。要使用 Python 的 argparse,您需要遵循以下四个简单的步骤:

\n
    \n
  1. 导入 argparse
  2. \n
  3. 通过实例化 ArgumentParser 创建参数解析器(argument parser);
  4. \n
  5. 使用 .add_argument() 方法向解析器添加参数(arguments)和选项(options);
  6. \n
  7. 在解析器上调用 .parse_args() 以获取参数 Namespace
  8. \n
\n

例如,您可以使用 argparse 来改进您的 ls_argv.py 脚本。现在,您可以创建一个名为 ls.py 的脚本,并编写以下代码:

\n
# ls.py v1\n\nimport argparse\nfrom pathlib import Path\n\nparser = argparse.ArgumentParser()\n\nparser.add_argument("path")\n\nargs = parser.parse_args()\n\ntarget_dir = Path(args.path)\n\nif not target_dir.exists():\n    print("The target directory doesn\'t exist")\n    raise SystemExit(1)\n\nfor entry in target_dir.iterdir():\n    print(entry.name)
\n

随着 argparse 的引入,您的代码发生了显著的变化。与之前的版本相比,最明显的不同是,用于检查用户提供的参数的条件语句已经消失了。这是因为 argparse 会自动为您检查参数的存在性。

\n

在这个新的实现中,您首先导入 argparse 并创建一个参数解析器。要创建解析器,您可以使用 ArgumentParser 类。接下来,您定义一个名为 path 的参数,用于获取用户的目标目录。

\n

接下来,您需要调用 .parse_args() 方法来解析输入参数,并获取一个包含所有用户参数的 Namespace 对象。请注意,现在 args 变量保存了一个 Namespace 对象,该对象具有从命令行收集的每个参数所对应的属性。

\n

在这个例子中,您只有一个参数,名为 pathNamespace 对象允许您使用点表示法通过 args 来访问 path。其余的代码与第一个实现相同。

\n

现在继续从命令行运行这个新脚本:

\n
$ python ls.py sample/\nlorem.md\nrealpython.md\nhello.txt\n\n$ python ls.py\nusage: ls.py [-h] path\nls.py: error: the following arguments are required: path\n\n$ python ls.py sample/ other_dir/\nusage: ls.py [-h] path\nls.py: error: unrecognized arguments: other_dir/\n\n$ python ls.py non_existing/\nThe target directory doesn\'t exist
\n

第一个命令的输出与您的原始脚本 ls_argv.py 相同。而第二个命令的输出则与 ls_argv.py 中的输出大不相同。程序现在会显示一个使用说明消息,并发出错误提示,告诉您必须提供 path 参数。

\n

在第三个命令中,您传递了两个目标目录,但应用程序并未为此做好准备。因此,它再次显示使用说明消息,并抛出一个错误,告知您潜在的问题。

\n

最后,如果您运行脚本时传递了一个不存在的目录作为参数,那么您会收到一个错误,告知您目标目录不存在,因此程序无法执行其工作。

\n

现在,您可以使用一个新的隐式特性。现在,您的程序接受一个可选的 -h 标志。不妨尝试一下:

\n
$ python ls.py -h\nusage: ls.py [-h] path\n\npositional arguments:\n  path\n\noptions:\n  -h, --help  show this help message and exit
\n

太棒了,现在您的程序会自动响应 -h--help 标志,并为您显示带有使用说明的帮助消息。这真是一个很棒的特性,而且您只需在代码中引入 argparse 就能轻松获得!

\n

经过这个快速介绍如何在 Python 中创建 CLI 应用后,您现在就可以深入研究 argparse 模块及其所有炫酷特性了。

\n

使用 Python 的 argparse 创建 CLI

\n

您可以使用 argparse 模块为您的应用程序和项目编写用户友好的命令行界面。该模块允许您定义应用程序所需的参数和选项。然后,argparse 将负责为您解析 sys.argv 的参数和选项。

\n

argparse 的另一个酷炫特性是它可以自动为您的 CLI 应用程序生成使用说明和帮助消息。该模块还会在参数无效时发出错误提示,并具备更多功能。

\n

在深入研究 argparse 之前,您需要知道该模块的文档可识别两种不同类型的命令行参数:

\n
    \n
  • 位置参数(Positional arguments),您称为参数(arguments);
  • \n
  • 可选参数(Optional arguments),即选项(options)、标志(flags)或开关(switches)。
  • \n
\n

ls.py 的示例中,path 是一个位置参数(positional argument)。这样的参数之所以被称为位置参数,是因为它在命令构造中的相对位置定义了其作用。

\n

与位置参数不同,可选参数(Optional arguments)并不是必需的。它们允许你修改命令的行为。以 Unix 命令 ls 为例,-l 标志就是一个可选参数,它使得命令以详细模式显示输出。

\n

在明确了这些概念之后,你就可以着手使用 Python 和 argparse 库来构建自己的命令行界面(CLI)应用程序了。

\n

创建命令行参数解析器

\n

命令行参数解析器是任何使用 argparse 的命令行界面(CLI)中最为关键的部分。你在命令行上提供的所有参数和选项都会经过这个解析器的处理,它会为你完成繁重的解析工作。

\n

要使用 argparse 创建命令行参数解析器,您需要实例化 ArgumentParser 类:

\n
>>> from argparse import ArgumentParser\n\n>>> parser = ArgumentParser()\n>>> parser\nArgumentParser(\n    prog=\'\',\n    usage=None,\n    description=None,\n    formatter_class=<class \'argparse.HelpFormatter\'>,\n    conflict_handler=\'error\',\n    add_help=True\n)
\n

ArgumentParser 的构造函数接受多种不同的参数,你可以利用这些参数来微调你的 CLI 的多个特性。由于所有这些参数都是可选的,因此你可以通过不传入任何参数直接实例化 ArgumentParser 来创建一个最基本的解析器。

\n

在本教程中,你将会更深入地了解 ArgumentParser 构造函数的参数,特别是在定制你的参数解析器的部分。目前,你可以开始使用 argparse 创建 CLI 的下一步了。这一步就是通过解析器对象来添加参数和选项。

\n

添加参数和选项

\n

要为 argparse 的 CLI 添加参数和选项,你将使用 ArgumentParser 实例的 .add_argument() 方法。请注意,这个方法对参数和选项都是通用的。在 argparse 的术语中,参数被称为位置参数(positional arguments),而选项被称为可选参数(optional arguments)。

\n

.add_argument() 方法的第一个参数决定了参数和选项之间的区别。这个参数被标识为名称(name)或标志(flag)。因此,如果你提供一个 name,那么你将定义一个参数(argument)。相反,如果你使用一个 flag,那么你将添加一个选项(option)。

\n

你已经在使用 argparse 时处理过命令行参数了。现在,考虑以下你自定义的 ls 命令的增强版本,它向 CLI 添加了一个 -l 选项:

\n
# ls.py v2\n\nimport argparse\nimport datetime\nfrom pathlib import Path\n\nparser = argparse.ArgumentParser()\n\nparser.add_argument("path")\n\nparser.add_argument("-l", "--long", action="store_true")\n\nargs = parser.parse_args()\n\ntarget_dir = Path(args.path)\n\nif not target_dir.exists():\n    print("The target directory doesn\'t exist")\n    raise SystemExit(1)\n\ndef build_output(entry, long=False):\n    if long:\n        size = entry.stat().st_size\n        date = datetime.datetime.fromtimestamp(\n            entry.stat().st_mtime).strftime(\n            "%b %d %H:%M:%S"\n        )\n        return f"{size:>6d} {date} {entry.name}"\n    return entry.name\n\nfor entry in target_dir.iterdir():\n    print(build_output(entry, long=args.long))
\n

在这个例子中,第 11 行代码创建了一个带有 -l--long 标志的选项。参数(arguments)和选项(options)在语法上的区别在于,选项名称以短横线 - 开头表示简写标志,以双短横线 -- 开头表示完整标志。

\n

请注意,在这个特定例子中,与 -l--long 选项一同设置了一个 action 参数为 "store_true",这意味着这个选项将存储一个布尔值。如果你在命令行上提供了这个选项,那么它的值将为 True。如果你省略了这个选项,那么它的值将为 False。在 "设置 Option 背后的 Action" 部分内容中,你将了解更多关于 .add_argument() 中的 action 参数的信息。

\n

在第 21 行的 build_output() 函数中,当 longTrue 时,它会返回一个详细的输出,否则返回一个简短的输出。详细的输出将包含目标目录中所有条目的大小、修改日期和名称。它使用了诸如 Path.stat() 这样的工具,以及带有自定义字符串格式的 datetime.datetime 对象。

\n

继续在 sample 上执行您的程序,以检查 -l 选项如何工作:

\n
$ python ls.py -l sample/\n  2609 Oct 28 14:07:04 lorem.md\n   428 Oct 28 14:07:04 realpython.md\n    83 Oct 28 14:07:04 hello.txt
\n

新增的 -l 选项允许你生成并显示关于目标目录内容的更详细输出。

\n

既然你已经知道了如何向 CLI 添加命令行参数和选项,接下来就是深入解析这些参数和选项的时候了。这将是你在接下来部分要探索的内容。

\n

解析命令行参数和选项

\n

解析命令行参数是基于 argparse 的任何 CLI 应用中的另一个重要步骤。一旦你解析了参数,你就可以根据它们的值来执行相应的操作。在你自定义的 ls 命令示例中,参数解析发生在包含 args = parser.parse_args() 语句的行上。

\n

这个语句调用了 .parse_args() 方法,并将其返回值赋给 args 变量。.parse_args() 的返回值是一个 Namespace 对象,其中包含了在命令行上提供的所有参数和选项以及它们对应的值。

\n

考虑以下简单的示例:

\n
>>> from argparse import ArgumentParser\n\n>>> parser = ArgumentParser()\n\n>>> parser.add_argument("site")\n_StoreAction(...)\n\n>>> parser.add_argument("-c", "--connect", action="store_true")\n_StoreTrueAction(...)\n\n>>> args = parser.parse_args(["Real Python", "-c"])\n>>> args\nNamespace(site=\'Real Python\', connect=True)\n\n>>> args.site\n\'Real Python\'\n>>> args.connect\nTrue
\n

通过在命令行参数解析器上调用 .parse_args() 方法得到的 Namespace 对象,你可以使用点表示法(dot notation)访问所有输入参数、选项以及它们对应的值。这样,你就可以检查输入参数和选项的列表,并根据用户在命令行上的选择来执行相应的操作。

\n

你将在应用程序的主代码中使用这个 Namespace 对象。这与你在自定义 ls 命令示例中的 for 循环下所做的类似。

\n

到目前为止,你已经了解了创建基于 argparse 的 CLI 的主要步骤。现在,你可以花些时间学习如何在 Python 中组织和构建 CLI 应用程序的基础知识了。

\n

设置 CLI 应用程序的布局和构建系统

\n

在继续你的 argparse 学习之旅之前,你应该暂停一下,思考如何组织你的代码和规划一个 CLI 项目。首先,你应该考虑以下几点:

\n
    \n
  • 你可以创建模块和包来组织代码。
  • \n
  • 你可以将 Python 应用的核心包命名为应用本身的名字。
  • \n
  • 你会根据每个 Python 模块的具体内容或功能来命名它们。
  • \n
  • 如果你希望某个包可以直接执行,你可以在该 Python 包中添加一个 __main__.py 模块。
  • \n
\n

将这些想法铭记于心,并考虑到模型-视图-控制器(MVC)模式是一种有效组织应用程序结构的方法,你在规划 CLI 项目时可以采用以下目录结构:

\n
hello_cli/\n│\n├── hello_cli/\n│   ├── __init__.py\n│   ├── __main__.py\n│   ├── cli.py\n│   └── model.py\n│\n├── tests/\n│   ├── __init__.py\n│   ├── test_cli.py\n│   └── test_model.py\n│\n├── pyproject.toml\n├── README.md\n└── requirements.txt\n
\n

hello_cli/ 目录是项目的根目录。在那里,您将放置以下文件:

\n
    \n
  • pyproject.toml 是一个 TOML 文件,用于指定项目的构建系统(build system)和其他配置(configurations)。
  • \n
  • README.md 文件提供了项目的描述以及安装和运行应用程序的说明。为你的项目添加一个描述性且详细的 README.md 文件是编程中的最佳实践,特别是如果你打算将项目作为开源解决方案发布的话。
  • \n
  • requirements.txt 是一个常规文件,列出了项目的外部依赖项(external dependencies)。你将使用这个文件,结合 pip-r 选项,来自动安装这些依赖项。
  • \n
\n

接下来是 hello_cli/ 目录,它包含了应用的核心包,该包包含以下模块:

\n
    \n
  • __init__.py 文件使得 hello_cli/ 可以作为一个 Python 包被识别。
  • \n
  • __main__.py 文件提供了应用程序的入口点脚本(entry-point script)或可执行文件,这是启动程序的主要入口。
  • \n
  • cli.py 文件为应用提供了命令行界面。在此文件中的代码将扮演基于 MVC 架构中的视图-控制器角色。
  • \n
  • model.py 文件包含了支持应用主要功能的代码。这部分代码将在你的 MVC 布局中扮演模型角色。
  • \n
\n

你还需要一个 tests/ 包,其中包含针对应用程序组件的单元测试文件。在这个具体的项目布局示例中,你有 test_cli.py 用于检查 CLI 功能的单元测试,以及 test_model.py 用于检查你的模型代码的单元测试。

\n

pyproject.toml 文件允许你定义应用程序的构建系统以及许多其他常规配置。以下是一个如何为你的示例 hello_cli 项目填写此文件的简单示例:

\n
# pyproject.toml\n\n[build-system]\nrequires = ["setuptools>=64.0.0", "wheel"]\nbuild-backend = "setuptools.build_meta"\n\n[project]\nname = "hello_cli"\nversion = "0.0.1"\ndescription = "My awesome Hello CLI application"\nreadme = "README.md"\nauthors = [{ name = "Real Python", email = "info@realpython.com" }]\n\n[project.scripts]\nhello_cli = "hello_cli.__main__:main"
\n

[build-system] 表头将 setuptools 设置为应用程序的构建系统,并指定 Python 需要安装哪些依赖项来构建应用程序。[project] 表头为你的应用提供了通用元数据。这些元数据在你想要将应用发布到 Python 包索引(PyPI)时非常有用。最后, [project.scripts] 表头定义了你的应用程序的入口点。

\n

经过这次对 CLI 项目布局和构建的快速探索,你已经准备好继续学习 argparse 了,特别是如何自定义你的命令行参数解析器。

\n

自定义你的命令行参数解析器

\n

在前面的部分中,你已经学习了如何使用 Python 的 argparse 模块为你的程序或应用实现命令行接口的基础知识。同时,你也了解了如何按照 MVC 模式组织和规划 CLI 应用项目。

\n

在接下来的部分中,你将更深入地探索 argparse 的许多其他强大功能。特别是,你将学习如何在 ArgumentParser 构造函数中使用一些最有用的参数,这将使你能够自定义 CLI 应用的一般行为。

\n

调整程序的 Help 和 Usage 内容

\n

向 CLI 应用程序的用户提供使用说明和帮助是一种最佳实践,可以通过出色的用户体验 (UX) 让用户更加愉快。在本节中,你将了解如何利用 ArgumentParser 的一些参数来微调 CLI 应用程序向用户显示帮助和使用消息的方式。你将学习如何:

\n
    \n
  • 设置程序名称
  • \n
  • 定义程序的描述和结束消息
  • \n
  • 对参数和选项进行分组显示帮助
  • \n
\n

首先,你将开始设置你的程序名称,并指定该名称在帮助或使用说明消息中的显示方式。

\n

设置程序名称

\n

默认情况下,argparse 会使用 sys.argv 中的第一个值来设置程序的名称。这个第一项包含你刚刚执行的 Python 文件的名称。这个文件名在使用说明消息中看起来会有些奇怪。

\n

例如,继续使用 -h 选项运行自定义 ls 命令:

\n
$ python ls.py -h\nusage: ls.py [-h] [-l] path\n\npositional arguments:\n  path\n\noptions:\n  -h, --help  show this help message and exit\n  -l, --long
\n

命令输出中的高亮行显示 argparse 正在使用文件名 ls.py 作为程序的名称。这看起来有些奇怪,因为在使用说明消息中,应用名称很少包含文件扩展名。

\n

幸运的是,你可以使用 prog 参数来指定你的程序名称,就像下面的代码片段所示:

\n
# ls.py v3\n\nimport argparse\nimport datetime\nfrom pathlib import Path\n\nparser = argparse.ArgumentParser(prog="ls")\n\n# ...\n\nfor entry in target_dir.iterdir():\n    print(build_output(entry, long=args.long))
\n

使用 prog 参数,你可以指定将在使用说明消息中使用的程序名称。在这个例子中,你使用了字符串 "ls"。现在,继续运行你的应用:

\n
$ python ls.py -h\nusage: ls [-h] [-l] path\n\npositional arguments:\n  path\n\noptions:\n  -h, --help  show this help message and exit\n  -l, --long
\n

很好!这个输出的第一行中的使用说明消息显示程序名称为 ls,而不是 ls.py

\n

除了设置程序名称外,argparse 还允许你定义应用的描述和结尾信息。在接下来的部分中,你将学习如何进行这两方面的操作。

\n

定义程序的描述和结语消息

\n

你还可以为你的应用定义一个通用的描述和一个结尾或结束语。为此,你将分别使用 descriptionepilog 参数。接下来,请更新 ls.py 文件,在 ArgumentParser 构造函数中添加以下内容:

\n
# ls.py v4\n\nimport argparse\nimport datetime\nfrom pathlib import Path\n\nparser = argparse.ArgumentParser(\n    prog="ls",\n    description="List the content of a directory",\n    epilog="Thanks for using %(prog)s! :)",\n)\n\n# ...\n\nfor entry in target_dir.iterdir():\n    print(build_output(entry, long=args.long))
\n

在这次更新中,description 参数允许你为应用提供一个通用的描述。这个描述将显示在帮助消息的开头。epilog 参数则允许你定义一些文本作为应用的结尾或结束语。请注意,你可以使用旧式的字符串格式化操作符(%)将 prog 参数插入到 epilog 字符串中。

\n

如果再次运行该应用程序,你将得到如下输出:

\n
$ python ls.py -h\nusage: ls [-h] [-l] path\n\nList the content of a directory\n\npositional arguments:\n  path\n\noptions:\n  -h, --help  show this help message and exit\n  -l, --long\n\nThanks for using ls! :)
\n

现在,输出会在使用消息之后显示描述消息,并在帮助文本末尾显示结语消息。

\n

显示参数和选项的分组帮助

\n

帮助分组(Help groups)是 argparse 的另一个有趣特性。它们允许你将相关的命令和参数进行分组,从而帮助你组织应用的帮助消息。要创建这些帮助分组,你将使用 ArgumentParser.add_argument_group() 方法。

\n

作为一个例子,请考虑你自定义的 ls 命令的以下更新版本:

\n
# ls.py v5\n# ...\n\nparser = argparse.ArgumentParser(\n    prog="ls",\n    description="List the content of a directory",\n    epilog="Thanks for using %(prog)s! :)",\n)\n\ngeneral = parser.add_argument_group("general output")\ngeneral.add_argument("path")\n\ndetailed = parser.add_argument_group("detailed output")\ndetailed.add_argument("-l", "--long", action="store_true")\n\nargs = parser.parse_args()\n\n# ...\n\nfor entry in target_dir.iterdir():\n    print(build_output(entry, long=args.long))
\n

在这次更新中,你为显示一般输出的参数和选项创建了一个帮助分组,并为显示详细输出的参数和选项创建了另一个分组。

\n

如果你在命令行中使用 -h 选项运行应用程序,那么你将获得以下输出:

\n
python ls.py -h\nusage: ls [-h] [-l] path\n\nList the content of a directory\n\noptions:\n  -h, --help  show this help message and exit\n\ngeneral output:\n  path\n\ndetailed output:\n  -l, --long\n\nThanks for using ls! :)
\n

现在,你的应用的参数和选项在帮助消息中以描述性的标题进行了方便的分组。这个整洁的特性将帮助你为用户提供更多的上下文,并帮助他们更好地理解应用的工作原理。

\n

为参数和选项提供全局设置

\n

除了自定义使用说明和帮助消息外,ArgumentParser 还允许你对命令行界面(CLI)应用进行其他一些有趣的调整。这些调整包括:

\n
    \n
  • 为参数和选项定义全局默认值
  • \n
  • 从外部文件中加载参数和选项
  • \n
  • 允许或禁止选项缩写
  • \n
\n

有时,你可能需要为你的应用的参数和选项指定一个全局默认值。你可以通过在调用 ArgumentParser 构造函数时,将默认值传递给 argument_default 参数来实现这一点(注意:实际上 ArgumentParser 没有 argument_default 这个参数,但这里是为了说明可以全局设置默认值的概念。在实际应用中,你可能需要为每个参数单独设置默认值)。

\n

这个特性可能并不常用,因为参数和选项通常具有不同的数据类型或意义,很难找到一个满足所有需求的值。

\n

然而,argument_default(尽管 ArgumentParser 并没有直接提供这个参数,但这里是为了说明概念)的一个常见用例是当你想要避免将参数和选项添加到 Namespace 对象中。在这种情况下,你可以使用 SUPPRESS 常量作为默认值。这个默认值将确保只有命令行中提供的参数和选项才会被存储在 argumentsNamespace 中。

\n

作为一个例子,请继续修改你的自定义 ls 命令,如下面的代码片段所示:

\n
# ls.py v6\n\nimport argparse\nimport datetime\nfrom pathlib import Path\n\nparser = argparse.ArgumentParser(\n    prog="ls",\n    description="List the content of a directory",\n    epilog="Thanks for using %(prog)s! :)",\n    argument_default=argparse.SUPPRESS,\n)\n\n# ...\n\nfor entry in target_dir.iterdir():\n    try:\n        long = args.long\n    except AttributeError:\n        long = False\n    print(build_output(entry, long=long))
\n

通过将 SUPPRESS 传递给 ArgumentParser 构造函数,你可以防止未提供的参数被存储在 argparse.Namespace 对象中。这就是为什么在调用 build_output() 之前,你需要检查 -l--long 选项是否实际被传递了。否则,你的代码会因为 args 中不存在 long 属性而引发 AttributeError 错误。

\n

ArgumentParser 的另一个酷炫功能是允许你从外部文件中加载参数值。当你有一个具有冗长或复杂的命令行结构的应用,并希望自动化加载参数值的过程时,这个功能就非常有用。

\n

在这种情况下,你可以将参数值存储在一个外部文件中,并让你的程序从该文件中加载它们。为了尝试这个功能,请继续创建一个简单的命令行界面(CLI)应用,如下所示:

\n
# fromfile.py\n\nimport argparse\n\nparser = argparse.ArgumentParser(fromfile_prefix_chars="@")\n\nparser.add_argument("one")\nparser.add_argument("two")\nparser.add_argument("three")\n\nargs = parser.parse_args()\n\nprint(args)
\n

在这里,你向 ArgumentParserfromfile_prefix_chars 参数传递 @ 符号。然后,你创建了三个必须在命令行中提供的必需参数。

\n

现在,假设你经常使用此应用程序,并且总是使用相同的一组参数值。为了简化和优化你的工作流程,你可以创建一个文件,其中包含所有必需参数的适当值,每个参数占一行,就像下面的 args.txt 文件一样:

\n
first\nsecond\nthird\n
\n

有了这个文件,您现在可以调用您的程序并指示它从 args.txt 文件加载值,如以下命令运行所示:

\n
$ python fromfile.py @args.txt\nNamespace(one=\'first\', two=\'second\', three=\'third\')
\n

在此命令的输出中,你可以看到 argparse 已经读取了 args.txt 的内容,并顺序地将值分配给了 fromfile.py 程序的每个参数。所有参数及其值都已成功存储在 Namespace 对象中。

\n

接受缩写选项名称的能力是 argparse 命令行界面(CLI)的另一个酷炫特性。这个特性是默认启用的,当你的程序具有长选项名称时非常有用。例如,考虑以下程序,它会在命令行下打印出你在 --argument-with-a-long-name 选项后指定的值:

\n
# abbreviate.py\n\nimport argparse\n\nparser = argparse.ArgumentParser()\n\nparser.add_argument("--argument-with-a-long-name")\n\nargs = parser.parse_args()\n\nprint(args.argument_with_a_long_name)
\n

这个程序会打印出你在 --argument-with-a-long-name 选项后传入的任何参数值。现在,请继续运行以下命令来检查 Python 的 argparse 模块如何处理这些缩写:

\n
$ python abbreviate.py --argument-with-a-long-name 42\n42\n\n$ python abbreviate.py --argument 42\n42\n\n$ python abbreviate.py --a 42\n42
\n

这些示例展示了如何缩写 --argument-with-a-long-name 选项的名称,而应用程序仍能正常工作。此功能是默认启用的。如果你希望禁用它并禁止缩写,那么可以在 ArgumentParser 中使用 allow_abbrev 参数:

\n
# abbreviate.py\n\nimport argparse\n\nparser = argparse.ArgumentParser(allow_abbrev=False)\n\nparser.add_argument("--argument-with-a-long-name")\n\nargs = parser.parse_args()\n\nprint(args.argument_with_a_long_name)
\n

allow_abbrev 设置为 False 会禁用命令行选项中的缩写。从这一点开始,你将需要为程序提供完整的选项名称才能正确工作。否则,你会收到一个错误:

\n
$ python abbreviate.py --argument-with-a-long-name 42\n42\n\n$ python abbreviate.py --argument 42\nusage: abbreviate.py [-h] [--argument-with-a-long-name ...]\nabbreviate.py: error: unrecognized arguments: --argument 42
\n

第二个示例中的错误消息告诉你 --argument 选项没有被识别为有效的选项。要使用该选项,你需要提供它的完整名称。

\n

微调你的命令行参数和选项

\n

到目前为止,你已经学习了如何定制 ArgumentParser 类的多个功能,以改善你的命令行界面(CLI)的用户体验。现在,你知道了如何调整你的应用程序的使用说明和帮助信息,以及如何微调命令行参数和选项的一些全局方面。

\n

在本节中,你将学习如何定制你的 CLI 的命令行参数和选项的其他几个功能。在这种情况下,你将使用 .add_argument() 方法及其一些最相关的参数,包括 actiontypenargsdefaulthelp 等。

\n

设置 Option 背后的 Action

\n

当你向命令行界面添加一个选项或标志时,通常需要定义如何将选项的值存储在调用 .parse_args() 后得到的 Namespace 对象中。为此,你会使用 .add_argument()action 参数。action 参数的默认值为 "store",意味着提供的选项值将原样存储在 Namespace 中。

\n

action 参数可以接受几个可能的值。以下是这些可能值的列表及其含义:

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.2-编程'}, 'labels': {'nodes': [{'name': '1.2.3-Python'}]}, 'comments': {'nodes': []}}, {'title': 'Chrome/Edge 地址栏正常显示完整的 URL', 'number': 74, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/74', 'createdAt': '2024-05-29T01:22:53Z', 'lastEditedAt': '2024-06-03T05:23:53Z', 'updatedAt': '2024-06-03T05:23:53Z', 'body': '对于在 Chrome/Edge 使用 IP 或者其他 URL 访问网页,地址栏想复制 IP/URL 非要给我自动加上 `http://`(或者 `https://`) 前缀。\r\n\r\n\r\n\r\n## Chrome\r\n\r\nGoogle Chrome 对于这个问题的解决方法很简单:在 URL 地址栏点击 "鼠标右键" -> 选择 "总是显示完整网址"。\r\n\r\n![chrome-show-url](https://kg.weiyan.cc/2024/06/chrome-show-url.png)\r\n\r\n## Edge\r\n\r\n1. 右键点击 Microsoft Edge 的桌面快捷方式,选择属性。\r\n ![edge-1](https://kg.weiyan.cc/2024/05/edge-1.png)\r\n\r\n2. 在启动目标结尾追加空格以及下面这段代码并保存。\r\n ```\r\n --disable-features=msHideSteadyStateUrlPath\r\n ```\r\n ![edge-disable-features](https://kg.weiyan.cc/2024/05/edge-disable-features.png)\r\n\r\n3. 重启浏览器后地址栏就可以显示完整 URL 了。', 'bodyText': '对于在 Chrome/Edge 使用 IP 或者其他 URL 访问网页,地址栏想复制 IP/URL 非要给我自动加上 http://(或者 https://) 前缀。\n\nChrome\nGoogle Chrome 对于这个问题的解决方法很简单:在 URL 地址栏点击 "鼠标右键" -> 选择 "总是显示完整网址"。\n\nEdge\n\n\n右键点击 Microsoft Edge 的桌面快捷方式,选择属性。\n\n\n\n在启动目标结尾追加空格以及下面这段代码并保存。\n--disable-features=msHideSteadyStateUrlPath\n\n\n\n\n重启浏览器后地址栏就可以显示完整 URL 了。', 'bodyHTML': '

对于在 Chrome/Edge 使用 IP 或者其他 URL 访问网页,地址栏想复制 IP/URL 非要给我自动加上 http://(或者 https://) 前缀。

\n\n

Chrome

\n

Google Chrome 对于这个问题的解决方法很简单:在 URL 地址栏点击 "鼠标右键" -> 选择 "总是显示完整网址"。

\n

chrome-show-url

\n

Edge

\n
    \n
  1. \n

    右键点击 Microsoft Edge 的桌面快捷方式,选择属性。
    \nedge-1

    \n
  2. \n
  3. \n

    在启动目标结尾追加空格以及下面这段代码并保存。

    \n
    --disable-features=msHideSteadyStateUrlPath\n
    \n

    edge-disable-features

    \n
  4. \n
  5. \n

    重启浏览器后地址栏就可以显示完整 URL 了。

    \n
  6. \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '适合我的 RSS 阅读器', 'number': 73, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/73', 'createdAt': '2024-05-21T05:51:39Z', 'lastEditedAt': '2024-05-21T06:16:08Z', 'updatedAt': '2024-05-21T06:18:31Z', 'body': '好多年前,写过一篇文章《[使用RSS打造你的科研资讯头条](https://zhuanlan.zhihu.com/p/42088810)》,但是由于没有趁手的 RSS 阅读器以至于让 RSS 信息聚合的这个念头荒废了好多年。直到最近用上了 [QiReader](https://github.com/oxyry/qireader) - 优雅的在线 RSS 阅读器,我的 RSS 信息聚合好像又找到了延续下去的动力。 \r\n\r\n\r\n\r\n不得不说,它很好的满足了我 Web 端+移动端同步的使用需求,而且国内国外通用。\r\n\r\n![qireader-twitter](https://kg.weiyan.cc/2024/05/qireader-twitter.png)\r\n\r\n在价格层面,一年 Pro 会员 ¥38,二年 ¥68,五年 ¥128,也不算贵 —— 于是,果断入手了。\r\n\r\n![qireader-plans](https://kg.weiyan.cc/2024/05/qireader-plans.webp)', 'bodyText': '好多年前,写过一篇文章《使用RSS打造你的科研资讯头条》,但是由于没有趁手的 RSS 阅读器以至于让 RSS 信息聚合的这个念头荒废了好多年。直到最近用上了 QiReader - 优雅的在线 RSS 阅读器,我的 RSS 信息聚合好像又找到了延续下去的动力。\n\n不得不说,它很好的满足了我 Web 端+移动端同步的使用需求,而且国内国外通用。\n\n在价格层面,一年 Pro 会员 ¥38,二年 ¥68,五年 ¥128,也不算贵 —— 于是,果断入手了。', 'bodyHTML': '

好多年前,写过一篇文章《使用RSS打造你的科研资讯头条》,但是由于没有趁手的 RSS 阅读器以至于让 RSS 信息聚合的这个念头荒废了好多年。直到最近用上了 QiReader - 优雅的在线 RSS 阅读器,我的 RSS 信息聚合好像又找到了延续下去的动力。

\n\n

不得不说,它很好的满足了我 Web 端+移动端同步的使用需求,而且国内国外通用。

\n

qireader-twitter

\n

在价格层面,一年 Pro 会员 ¥38,二年 ¥68,五年 ¥128,也不算贵 —— 于是,果断入手了。

\n

qireader-plans

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'Twitter', 'number': 72, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/72', 'createdAt': '2024-05-16T01:58:18Z', 'lastEditedAt': '2024-05-28T03:22:30Z', 'updatedAt': '2024-05-28T03:22:30Z', 'body': '相比微博,Twitter 更有意思一些,除了可以获取到很多技术大咖的日常和动态,还能发现不少有意思的人和事。加上推特世界性的,开放性的一些特点,所以可以看到的自然是什么都有也比国内精彩。\r\n\r\n\r\n\r\n能够翻出来的都是有点认知的人,虽然不一定全对,但也有一定道理。\r\n\r\n微博用的比较少,感觉更加偏向娱乐和一些时事热点。', 'bodyText': '相比微博,Twitter 更有意思一些,除了可以获取到很多技术大咖的日常和动态,还能发现不少有意思的人和事。加上推特世界性的,开放性的一些特点,所以可以看到的自然是什么都有也比国内精彩。\n\n能够翻出来的都是有点认知的人,虽然不一定全对,但也有一定道理。\n微博用的比较少,感觉更加偏向娱乐和一些时事热点。', 'bodyHTML': '

相比微博,Twitter 更有意思一些,除了可以获取到很多技术大咖的日常和动态,还能发现不少有意思的人和事。加上推特世界性的,开放性的一些特点,所以可以看到的自然是什么都有也比国内精彩。

\n\n

能够翻出来的都是有点认知的人,虽然不一定全对,但也有一定道理。

\n

微博用的比较少,感觉更加偏向娱乐和一些时事热点。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'mamba 的两个分支 miniforge 和 mambaforge', 'number': 71, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/71', 'createdAt': '2024-04-28T02:44:00Z', 'lastEditedAt': '2024-06-26T03:00:57Z', 'updatedAt': '2024-06-26T03:00:57Z', 'body': "在安装 mamba 的时候在 [release](https://github.com/conda-forge/miniforge/releases) 页面和[官方的安装页面](https://mamba.readthedocs.io/en/latest/installation/mamba-installation.html) 总是看到关于 miniforge 和 mambaforge 的选择问题,傻傻搞不明白。\r\n\r\n\r\n\r\n## Miniforge 和 Mambaforge\r\n\r\n参考:\r\n\r\n> **What's the difference between Mambaforge and Miniforge?** \r\n> After the release of Miniforge 23.3.1 in August 2023, Miniforge and Mambaforge are essentially identical. The only difference is the name of the installer and subsequently the default installation path.\r\n> \r\n> 2023 年 8 月发布 Miniforge 23.3.1 后,Miniforge 和 Mambaforge 基本相同。唯一的区别是安装程序的名称以及随后的默认安装路径(一个默认是 miniforge3,一个默认是 mambaforge3)。\r\n> \r\n> Before that release, Miniforge only shipped conda, while Mambaforge added mamba on top. Since Miniconda started shipping conda-libmamba-solver in July 2023, Miniforge followed suit and started shipping it too in August. At that point, since conda-libmamba-solver depends on libmambapy, the only difference between Miniforge and Mambaforge was the presence of the mamba Python package. To minimize surprises, we decided to add mamba to Miniforge too. \r\n> \r\n> 在之前的版本中,Miniforge 仅提供 conda,而 Mambaforge 在此基础上增加了 mamba。自 2023 年 7 月 Miniconda 开始提供 conda-libmamba-solver 以来,Miniforge 也紧随其后,于 8 月开始提供此功能。那时,由于 conda-libmamba-solver 依赖于libmambapy,Miniforge 和 Mambaforge 之间的唯一区别就是是否包含 mamba Pytho n包。为了尽量减少意外情况,我们决定也在 Miniforge 中添加 mamba。\r\n> \r\n> **Should I choose one or another going forward at the risk of one of them gettting deprecated?** \r\n> Given its wide usage, there are no plans to deprecate Mambaforge. If at some point we decide to deprecate Mambaforge, it will be appropriately announced and communicated with sufficient time in advance.\r\n> \r\n> 鉴于 Mambaforge 的广泛使用,目前没有计划将其弃用。如果未来我们决定弃用 Mambaforge,我们会提前充分公告并通知相关用户。\r\n> \r\n> That said, if you had to start using one today, we recommend to stick to Miniforge.\r\n> \r\n> 不过,如果你今天需要开始使用其中一个,我们建议你坚持使用 Miniforge。\r\n\r\n## Miniforge 和 Miniconda\r\n\r\n参考:[What’s the difference between Anaconda, conda, Miniconda, mamba, Mambaforge, micromamba?](https://bioconda.github.io/faqs.html#what-s-the-difference-between-anaconda-conda-miniconda-mamba-mambaforge-micromamba) - bioconda#Faqs\r\n\r\nMiniforge 是社区 (conda-forge) 驱动的简约 conda 安装程序。Miniforge 与 Miniconda 类似,但预配置了 `conda-forge` 通道,并且所有包都来自 conda-forge 而不是 `defaults` 通道。现在它还包含了 mamba 和 libmamba。\r\n\r\nMiniconda 是公司 (Anaconda) 驱动的简约 conda 安装程序。随后的软件包安装来自 anaconda 频道(默认或其他)。\r\n\r\n## 一句话\r\n\r\n总的一句话来说,Mambaforge 类似于 Miniforge,但将 mamba 安装到基础环境中。虽然没有严格弃用,但从 **2023 年 9 月**起不鼓励使用它(请参阅 miniforge 自述 [README](https://github.com/conda-forge/miniforge) 文件)。\r\n\r\n\r\n", 'bodyText': "在安装 mamba 的时候在 release 页面和官方的安装页面 总是看到关于 miniforge 和 mambaforge 的选择问题,傻傻搞不明白。\n\nMiniforge 和 Mambaforge\n参考:https://github.com/conda-forge/miniforge?tab=readme-ov-file#faq\n\nWhat's the difference between Mambaforge and Miniforge?\nAfter the release of Miniforge 23.3.1 in August 2023, Miniforge and Mambaforge are essentially identical. The only difference is the name of the installer and subsequently the default installation path.\n2023 年 8 月发布 Miniforge 23.3.1 后,Miniforge 和 Mambaforge 基本相同。唯一的区别是安装程序的名称以及随后的默认安装路径(一个默认是 miniforge3,一个默认是 mambaforge3)。\nBefore that release, Miniforge only shipped conda, while Mambaforge added mamba on top. Since Miniconda started shipping conda-libmamba-solver in July 2023, Miniforge followed suit and started shipping it too in August. At that point, since conda-libmamba-solver depends on libmambapy, the only difference between Miniforge and Mambaforge was the presence of the mamba Python package. To minimize surprises, we decided to add mamba to Miniforge too.\n在之前的版本中,Miniforge 仅提供 conda,而 Mambaforge 在此基础上增加了 mamba。自 2023 年 7 月 Miniconda 开始提供 conda-libmamba-solver 以来,Miniforge 也紧随其后,于 8 月开始提供此功能。那时,由于 conda-libmamba-solver 依赖于libmambapy,Miniforge 和 Mambaforge 之间的唯一区别就是是否包含 mamba Pytho n包。为了尽量减少意外情况,我们决定也在 Miniforge 中添加 mamba。\nShould I choose one or another going forward at the risk of one of them gettting deprecated?\nGiven its wide usage, there are no plans to deprecate Mambaforge. If at some point we decide to deprecate Mambaforge, it will be appropriately announced and communicated with sufficient time in advance.\n鉴于 Mambaforge 的广泛使用,目前没有计划将其弃用。如果未来我们决定弃用 Mambaforge,我们会提前充分公告并通知相关用户。\nThat said, if you had to start using one today, we recommend to stick to Miniforge.\n不过,如果你今天需要开始使用其中一个,我们建议你坚持使用 Miniforge。\n\nMiniforge 和 Miniconda\n参考:What’s the difference between Anaconda, conda, Miniconda, mamba, Mambaforge, micromamba? - bioconda#Faqs\nMiniforge 是社区 (conda-forge) 驱动的简约 conda 安装程序。Miniforge 与 Miniconda 类似,但预配置了 conda-forge 通道,并且所有包都来自 conda-forge 而不是 defaults 通道。现在它还包含了 mamba 和 libmamba。\nMiniconda 是公司 (Anaconda) 驱动的简约 conda 安装程序。随后的软件包安装来自 anaconda 频道(默认或其他)。\n一句话\n总的一句话来说,Mambaforge 类似于 Miniforge,但将 mamba 安装到基础环境中。虽然没有严格弃用,但从 2023 年 9 月起不鼓励使用它(请参阅 miniforge 自述 README 文件)。", 'bodyHTML': '

在安装 mamba 的时候在 release 页面和官方的安装页面 总是看到关于 miniforge 和 mambaforge 的选择问题,傻傻搞不明白。

\n\n

Miniforge 和 Mambaforge

\n

参考:https://github.com/conda-forge/miniforge?tab=readme-ov-file#faq

\n
\n

What\'s the difference between Mambaforge and Miniforge?
\nAfter the release of Miniforge 23.3.1 in August 2023, Miniforge and Mambaforge are essentially identical. The only difference is the name of the installer and subsequently the default installation path.

\n

2023 年 8 月发布 Miniforge 23.3.1 后,Miniforge 和 Mambaforge 基本相同。唯一的区别是安装程序的名称以及随后的默认安装路径(一个默认是 miniforge3,一个默认是 mambaforge3)。

\n

Before that release, Miniforge only shipped conda, while Mambaforge added mamba on top. Since Miniconda started shipping conda-libmamba-solver in July 2023, Miniforge followed suit and started shipping it too in August. At that point, since conda-libmamba-solver depends on libmambapy, the only difference between Miniforge and Mambaforge was the presence of the mamba Python package. To minimize surprises, we decided to add mamba to Miniforge too.

\n

在之前的版本中,Miniforge 仅提供 conda,而 Mambaforge 在此基础上增加了 mamba。自 2023 年 7 月 Miniconda 开始提供 conda-libmamba-solver 以来,Miniforge 也紧随其后,于 8 月开始提供此功能。那时,由于 conda-libmamba-solver 依赖于libmambapy,Miniforge 和 Mambaforge 之间的唯一区别就是是否包含 mamba Pytho n包。为了尽量减少意外情况,我们决定也在 Miniforge 中添加 mamba。

\n

Should I choose one or another going forward at the risk of one of them gettting deprecated?
\nGiven its wide usage, there are no plans to deprecate Mambaforge. If at some point we decide to deprecate Mambaforge, it will be appropriately announced and communicated with sufficient time in advance.

\n

鉴于 Mambaforge 的广泛使用,目前没有计划将其弃用。如果未来我们决定弃用 Mambaforge,我们会提前充分公告并通知相关用户。

\n

That said, if you had to start using one today, we recommend to stick to Miniforge.

\n

不过,如果你今天需要开始使用其中一个,我们建议你坚持使用 Miniforge。

\n
\n

Miniforge 和 Miniconda

\n

参考:What’s the difference between Anaconda, conda, Miniconda, mamba, Mambaforge, micromamba? - bioconda#Faqs

\n

Miniforge 是社区 (conda-forge) 驱动的简约 conda 安装程序。Miniforge 与 Miniconda 类似,但预配置了 conda-forge 通道,并且所有包都来自 conda-forge 而不是 defaults 通道。现在它还包含了 mamba 和 libmamba。

\n

Miniconda 是公司 (Anaconda) 驱动的简约 conda 安装程序。随后的软件包安装来自 anaconda 频道(默认或其他)。

\n

一句话

\n

总的一句话来说,Mambaforge 类似于 Miniforge,但将 mamba 安装到基础环境中。虽然没有严格弃用,但从 2023 年 9 月起不鼓励使用它(请参阅 miniforge 自述 README 文件)。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '1.3.22-虚拟环境'}]}, 'comments': {'nodes': []}}, {'title': '寻找 GitHub 的替代品', 'number': 70, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/70', 'createdAt': '2024-04-24T02:15:48Z', 'lastEditedAt': '2024-09-05T02:18:00Z', 'updatedAt': '2024-09-05T02:18:00Z', 'body': '与其说是在寻找 GitHub 的替代品,倒不如说在寻找 GitHub 的备用站点 —— 以防万一 GitHub 哪天登不上去了,也不至于把托管在上面的东西都丢了,尤其对于我这种几乎把所有可公开文档都记录在 [GitHub Discussions](https://github.com/shenweiyan/Knowledge-Garden/discussions) 上的人,毕竟把所有的鸡蛋放在一个篮子里终究是很危险的。\r\n\r\n\r\n\r\n## 代码\r\n\r\n如果纯粹是代码托管,这样的备用平台多的是。\r\n\r\n除去国内的那几家,国外优秀的托管平台更多一些。如 [Framagit](https://framagit.org/) 和 [Codeberg](https://codeberg.org/)。[Framagit](https://framagit.org/) 是一个基于 GitLab 的法国托管平台,而 [Codeberg](https://codeberg.org/) 则是一个站点(总部)在德国,由非盈利组织采用自由软件(Gitea)搭建的代码托管平台,两相比较,个人感觉 [Codeberg](https://codeberg.org/) 比 [Framagit](https://framagit.org/) 体验更友好,最起码文档和各种导航操作更加清晰明了。\r\n\r\n最最重要的一点是,这两个托管平台目前国内都可以直接连接。\r\n\r\n## Issues 和 Discussions\r\n\r\n如果说 Issues 和 Discussions 的备用站点,这个就不好说了。国内的 [GitCode](https://gitcode.com/) 和 [AtomGit](https://atomgit.com/) 虽然都有类似的功能,但是**都不能搜索内容**,虽然他们说全文搜索已经[在路上了](https://atomgit.com/atomgit_operate/feedback/issues/496),但是背后的 CSDN 运营和 UI 风格真是让人有点担忧重蹈 CSDN 的尿性体验。\r\n\r\n尤其是最近(2024年6月)这一段时间 GitCode 被曝[批量搬运 Github 项目](https://www.ithome.com/0/778/049.htm)的事件,让本来对 CSDN 厌恶至极的我瞬间好感全无,开始对 GitCode 也时刻保持警戒心态。\r\n\r\n## Pages\r\n\r\nGitee Pages 在五一[悄悄关停了](https://gitee.com/oschina/git-osc/issues/I9L5FJ) 也终于让人对国内代码托管平台开启 Pages 服务不再抱有期待。虽然最近发现 [AtomGit](https://atomgit.com/) 也提供了 [AtomGit Pages](https://atomgit.com/apps/pages),而且也的确能正常的用起来了,但谁能确保未来会不会也跟 Gitee Pages 一个下场!\r\n\r\n![atomgit-pages-for-atomgit](https://kg.weiyan.cc/2024/07/atomgit-pages-for-atomgit.jpg)\r\n\r\n## 想法\r\n\r\n由于国内监管的一些问题,国内的开源社区大多都让人一言难尽,曾经的极狐也因为收费的问题把个人用户的最后一根稻草给压垮了,总的来说,国内目前为止就还没有一家能跟得上 GitHub/GitLab 的开源平台,不管从开源本身还是功能体验,现在没有,未来也不一定能有。\r\n\r\n用了一段时间 AtomGit,页面 UI 真是无法忍受,一堆的 BUG 毫无修复([issues#442](https://atomgit.com/atomgit_operate/feedback/issues/442)、[issues#668](https://atomgit.com/atomgit_operate/feedback/issues/668)),用户体验全无。还是先在 GitCode,继续苟着吧!', 'bodyText': '与其说是在寻找 GitHub 的替代品,倒不如说在寻找 GitHub 的备用站点 —— 以防万一 GitHub 哪天登不上去了,也不至于把托管在上面的东西都丢了,尤其对于我这种几乎把所有可公开文档都记录在 GitHub Discussions 上的人,毕竟把所有的鸡蛋放在一个篮子里终究是很危险的。\n\n代码\n如果纯粹是代码托管,这样的备用平台多的是。\n除去国内的那几家,国外优秀的托管平台更多一些。如 Framagit 和 Codeberg。Framagit 是一个基于 GitLab 的法国托管平台,而 Codeberg 则是一个站点(总部)在德国,由非盈利组织采用自由软件(Gitea)搭建的代码托管平台,两相比较,个人感觉 Codeberg 比 Framagit 体验更友好,最起码文档和各种导航操作更加清晰明了。\n最最重要的一点是,这两个托管平台目前国内都可以直接连接。\nIssues 和 Discussions\n如果说 Issues 和 Discussions 的备用站点,这个就不好说了。国内的 GitCode 和 AtomGit 虽然都有类似的功能,但是都不能搜索内容,虽然他们说全文搜索已经在路上了,但是背后的 CSDN 运营和 UI 风格真是让人有点担忧重蹈 CSDN 的尿性体验。\n尤其是最近(2024年6月)这一段时间 GitCode 被曝批量搬运 Github 项目的事件,让本来对 CSDN 厌恶至极的我瞬间好感全无,开始对 GitCode 也时刻保持警戒心态。\nPages\nGitee Pages 在五一悄悄关停了 也终于让人对国内代码托管平台开启 Pages 服务不再抱有期待。虽然最近发现 AtomGit 也提供了 AtomGit Pages,而且也的确能正常的用起来了,但谁能确保未来会不会也跟 Gitee Pages 一个下场!\n\n想法\n由于国内监管的一些问题,国内的开源社区大多都让人一言难尽,曾经的极狐也因为收费的问题把个人用户的最后一根稻草给压垮了,总的来说,国内目前为止就还没有一家能跟得上 GitHub/GitLab 的开源平台,不管从开源本身还是功能体验,现在没有,未来也不一定能有。\n用了一段时间 AtomGit,页面 UI 真是无法忍受,一堆的 BUG 毫无修复(issues#442、issues#668),用户体验全无。还是先在 GitCode,继续苟着吧!', 'bodyHTML': '

与其说是在寻找 GitHub 的替代品,倒不如说在寻找 GitHub 的备用站点 —— 以防万一 GitHub 哪天登不上去了,也不至于把托管在上面的东西都丢了,尤其对于我这种几乎把所有可公开文档都记录在 GitHub Discussions 上的人,毕竟把所有的鸡蛋放在一个篮子里终究是很危险的。

\n\n

代码

\n

如果纯粹是代码托管,这样的备用平台多的是。

\n

除去国内的那几家,国外优秀的托管平台更多一些。如 FramagitCodebergFramagit 是一个基于 GitLab 的法国托管平台,而 Codeberg 则是一个站点(总部)在德国,由非盈利组织采用自由软件(Gitea)搭建的代码托管平台,两相比较,个人感觉 CodebergFramagit 体验更友好,最起码文档和各种导航操作更加清晰明了。

\n

最最重要的一点是,这两个托管平台目前国内都可以直接连接。

\n

Issues 和 Discussions

\n

如果说 Issues 和 Discussions 的备用站点,这个就不好说了。国内的 GitCodeAtomGit 虽然都有类似的功能,但是都不能搜索内容,虽然他们说全文搜索已经在路上了,但是背后的 CSDN 运营和 UI 风格真是让人有点担忧重蹈 CSDN 的尿性体验。

\n

尤其是最近(2024年6月)这一段时间 GitCode 被曝批量搬运 Github 项目的事件,让本来对 CSDN 厌恶至极的我瞬间好感全无,开始对 GitCode 也时刻保持警戒心态。

\n

Pages

\n

Gitee Pages 在五一悄悄关停了 也终于让人对国内代码托管平台开启 Pages 服务不再抱有期待。虽然最近发现 AtomGit 也提供了 AtomGit Pages,而且也的确能正常的用起来了,但谁能确保未来会不会也跟 Gitee Pages 一个下场!

\n

atomgit-pages-for-atomgit

\n

想法

\n

由于国内监管的一些问题,国内的开源社区大多都让人一言难尽,曾经的极狐也因为收费的问题把个人用户的最后一根稻草给压垮了,总的来说,国内目前为止就还没有一家能跟得上 GitHub/GitLab 的开源平台,不管从开源本身还是功能体验,现在没有,未来也不一定能有。

\n

用了一段时间 AtomGit,页面 UI 真是无法忍受,一堆的 BUG 毫无修复(issues#442issues#668),用户体验全无。还是先在 GitCode,继续苟着吧!

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': [{'name': '公众号'}]}, 'comments': {'nodes': []}}, {'title': '我的独立站点 Knowledge-Garden', 'number': 69, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/69', 'createdAt': '2024-04-22T07:37:31Z', 'lastEditedAt': '2024-04-22T07:38:53Z', 'updatedAt': '2024-04-22T07:38:53Z', 'body': '使用 GitHub Discussions 写作文章大半年以来,越来越得心应手,最近起用了新的一个仓库,用于 [Knowledge-Garden](https://github.com/shenweiyan/Knowledge-Garden/discussions) 静态资源的保存和使用。\r\n\r\n\r\n\r\n## 文章\r\n\r\n所有的文章都是以 markdown 的格式进行保存,实际上就一堆 text 文本,占用不了多少的空间。\r\n\r\n## 静态资源\r\n\r\n文章的静态资源,主要是图片,才是一个最耗流量和存储空间的东西。\r\n\r\n前一段时间经历了[腾讯云 cos 对象存储被盗刷](https://github.com/shenweiyan/Knowledge-Garden/discussions/63) 的事件后,对于对象存储的使用也就越来越谨慎,今天终于狠下决心来把 [Knowledge-Garden](https://github.com/shenweiyan/Knowledge-Garden/discussions) 这个仓库的所有包括图片在内的静态资源开始保存到另外一个 GitHub 仓库 [PicKG](https://github.com/shenweiyan/PicKG),同时借助 Cloudflare Pages 来为图片提供访问链接。\r\n\r\n也尝试了一下 Cloudflare 的 [R2](https://www.cloudflare.com/zh-cn/developer-platform/r2/) 这个号称零出口费用的对象存储,免费额度很有吸引力,但目前 Cloudflare R2 还没能找到一个比较顺手的图片管理工具,例如阿里云的 [oss-browser](https://github.com/aliyun/oss-browser)、腾讯云的 [cos-browser](https://cosbrowser.cloud.tencent.com/)。虽然尝试了一些折中的方案,如 [Picx4R2](https://github.com/shenweiyan/Picx4R2),但还是不太满意。\r\n\r\n所以目前的解决方法就是 GitHub + [PicX](https://github.com/shenweiyan/Knowledge-Garden/discussions/68) + Cloudflare Pages 进行组合,GitHub 单个仓库 5G 的存储空间应该应该也足够使用了,如果实在不够了再来考虑其他方案。', 'bodyText': '使用 GitHub Discussions 写作文章大半年以来,越来越得心应手,最近起用了新的一个仓库,用于 Knowledge-Garden 静态资源的保存和使用。\n\n文章\n所有的文章都是以 markdown 的格式进行保存,实际上就一堆 text 文本,占用不了多少的空间。\n静态资源\n文章的静态资源,主要是图片,才是一个最耗流量和存储空间的东西。\n前一段时间经历了腾讯云 cos 对象存储被盗刷 的事件后,对于对象存储的使用也就越来越谨慎,今天终于狠下决心来把 Knowledge-Garden 这个仓库的所有包括图片在内的静态资源开始保存到另外一个 GitHub 仓库 PicKG,同时借助 Cloudflare Pages 来为图片提供访问链接。\n也尝试了一下 Cloudflare 的 R2 这个号称零出口费用的对象存储,免费额度很有吸引力,但目前 Cloudflare R2 还没能找到一个比较顺手的图片管理工具,例如阿里云的 oss-browser、腾讯云的 cos-browser。虽然尝试了一些折中的方案,如 Picx4R2,但还是不太满意。\n所以目前的解决方法就是 GitHub + PicX + Cloudflare Pages 进行组合,GitHub 单个仓库 5G 的存储空间应该应该也足够使用了,如果实在不够了再来考虑其他方案。', 'bodyHTML': '

使用 GitHub Discussions 写作文章大半年以来,越来越得心应手,最近起用了新的一个仓库,用于 Knowledge-Garden 静态资源的保存和使用。

\n\n

文章

\n

所有的文章都是以 markdown 的格式进行保存,实际上就一堆 text 文本,占用不了多少的空间。

\n

静态资源

\n

文章的静态资源,主要是图片,才是一个最耗流量和存储空间的东西。

\n

前一段时间经历了腾讯云 cos 对象存储被盗刷 的事件后,对于对象存储的使用也就越来越谨慎,今天终于狠下决心来把 Knowledge-Garden 这个仓库的所有包括图片在内的静态资源开始保存到另外一个 GitHub 仓库 PicKG,同时借助 Cloudflare Pages 来为图片提供访问链接。

\n

也尝试了一下 Cloudflare 的 R2 这个号称零出口费用的对象存储,免费额度很有吸引力,但目前 Cloudflare R2 还没能找到一个比较顺手的图片管理工具,例如阿里云的 oss-browser、腾讯云的 cos-browser。虽然尝试了一些折中的方案,如 Picx4R2,但还是不太满意。

\n

所以目前的解决方法就是 GitHub + PicX + Cloudflare Pages 进行组合,GitHub 单个仓库 5G 的存储空间应该应该也足够使用了,如果实在不够了再来考虑其他方案。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '部署 PicX 图床到 Vercel', 'number': 68, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/68', 'createdAt': '2024-04-22T03:29:53Z', 'lastEditedAt': '2024-05-28T01:50:54Z', 'updatedAt': '2024-05-28T01:50:54Z', 'body': '由于 [PicX](https://github.com/XPoet/picx) 自 v3.0 起,不再支持自由选择仓库和分支,统一使用内置的仓库和分支。所以出于自定义的仓库和分支使用需求,这里主要对 [PicX v2.0](https://github.com/XPoet/picx/tree/v2) 进行 Vercel 自定义部署。\r\n\r\n\r\n\r\n项目地址:https://github.com/XPoet/picx/tree/v2\r\n\r\n利用 PicX 图床,直接把图片托管到 GitHub 上去。至于安装,参考[子舒 Blog](https://zburu.com/)的《[安装一个基于 Github 的静态图床程序](https://zburu.com/blog/172.html/)》这两篇文章。可以把程序和图床直接托管在 GitHub 上,也可以把程序搭建在自己的服务器上,但是图片还是只能托管到 GitHub 上。PicX 图床不像简单图床和兰空图床,图片生成的链接可以是自己的域名链接,而因为图片是托管到 GitHub 上,所以 PicX 生成的图片外链接只能是 staticaly 和 cloudfalre 的 CDN 的外链。所以个人感觉也就没有必要再把程序上传到自己的服务器上了,直接使用 GitHub 不是更好嘛。\r\n\r\n## 操作步骤\r\n\r\n主要的操作步骤如下: \r\n\r\n- 1 个 GitHub 账号;\r\n- 1 个 Vercel 账号,可能需要科学上网环境;\r\n- Fork PicX v2 源码 (https://github.com/XPoet/picx/tree/v2) 到个人 GitHub 仓库;\r\n- 在 Vercel 新建项目,绑定个人 GitHub 仓库的 PicX v2 源码;Framework Preset 选择 "Vue.js";\r\n- 部署完成后为域名添加一条 CNAME 到 `cname-china.vercel-dns.com`。\r\n\r\n基于以上的步骤,个人成功部署的一个 PicX 站点,以供参考和使用:\r\n\r\n- https://github.com/shenweiyan/PicX\r\n- 链接1:\r\n- 链接2:\r\n\r\n![picx-weiyan-cc](https://kg.weiyan.cc/2024/05/picx-weiyan-cc.webp)', 'bodyText': '由于 PicX 自 v3.0 起,不再支持自由选择仓库和分支,统一使用内置的仓库和分支。所以出于自定义的仓库和分支使用需求,这里主要对 PicX v2.0 进行 Vercel 自定义部署。\n\n项目地址:https://github.com/XPoet/picx/tree/v2\n利用 PicX 图床,直接把图片托管到 GitHub 上去。至于安装,参考子舒 Blog的《安装一个基于 Github 的静态图床程序》这两篇文章。可以把程序和图床直接托管在 GitHub 上,也可以把程序搭建在自己的服务器上,但是图片还是只能托管到 GitHub 上。PicX 图床不像简单图床和兰空图床,图片生成的链接可以是自己的域名链接,而因为图片是托管到 GitHub 上,所以 PicX 生成的图片外链接只能是 staticaly 和 cloudfalre 的 CDN 的外链。所以个人感觉也就没有必要再把程序上传到自己的服务器上了,直接使用 GitHub 不是更好嘛。\n操作步骤\n主要的操作步骤如下:\n\n1 个 GitHub 账号;\n1 个 Vercel 账号,可能需要科学上网环境;\nFork PicX v2 源码 (https://github.com/XPoet/picx/tree/v2) 到个人 GitHub 仓库;\n在 Vercel 新建项目,绑定个人 GitHub 仓库的 PicX v2 源码;Framework Preset 选择 "Vue.js";\n部署完成后为域名添加一条 CNAME 到 cname-china.vercel-dns.com。\n\n基于以上的步骤,个人成功部署的一个 PicX 站点,以供参考和使用:\n\nhttps://github.com/shenweiyan/PicX\n链接1:https://v2picx.vercel.app/\n链接2:https://picx.weiyan.cc/', 'bodyHTML': '

由于 PicX 自 v3.0 起,不再支持自由选择仓库和分支,统一使用内置的仓库和分支。所以出于自定义的仓库和分支使用需求,这里主要对 PicX v2.0 进行 Vercel 自定义部署。

\n\n

项目地址:https://github.com/XPoet/picx/tree/v2

\n

利用 PicX 图床,直接把图片托管到 GitHub 上去。至于安装,参考子舒 Blog的《安装一个基于 Github 的静态图床程序》这两篇文章。可以把程序和图床直接托管在 GitHub 上,也可以把程序搭建在自己的服务器上,但是图片还是只能托管到 GitHub 上。PicX 图床不像简单图床和兰空图床,图片生成的链接可以是自己的域名链接,而因为图片是托管到 GitHub 上,所以 PicX 生成的图片外链接只能是 staticaly 和 cloudfalre 的 CDN 的外链。所以个人感觉也就没有必要再把程序上传到自己的服务器上了,直接使用 GitHub 不是更好嘛。

\n

操作步骤

\n

主要的操作步骤如下:

\n
    \n
  • 1 个 GitHub 账号;
  • \n
  • 1 个 Vercel 账号,可能需要科学上网环境;
  • \n
  • Fork PicX v2 源码 (https://github.com/XPoet/picx/tree/v2) 到个人 GitHub 仓库;
  • \n
  • 在 Vercel 新建项目,绑定个人 GitHub 仓库的 PicX v2 源码;Framework Preset 选择 "Vue.js";
  • \n
  • 部署完成后为域名添加一条 CNAME 到 cname-china.vercel-dns.com
  • \n
\n

基于以上的步骤,个人成功部署的一个 PicX 站点,以供参考和使用:

\n\n

picx-weiyan-cc

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '国内静态部署与托管平台', 'number': 67, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/67', 'createdAt': '2024-04-15T07:19:16Z', 'lastEditedAt': None, 'updatedAt': '2024-04-15T07:22:22Z', 'body': '[Gitee Pages](https://gitee.com/help/articles/4136/) 由于审查原因,基本上已经是名存实亡的状态了;之前勉强可以使用的 [Webbify](https://webify.cloudbase.net/) 现如今也变成了每月至少 15 块的购买时长模式。\r\n\r\n\r\n\r\n之前在《[越来越难用的国内代码托管平台](https://github.com/shenweiyan/Knowledge-Garden/discussions/56)》吐槽过一波国内所谓开源平台的状况,今天又发现除了代码平台外,原来静态部署的平台也走上了这一条路。\r\n\r\n[Gitee Pages](https://gitee.com/help/articles/4136/) 就不说了,懂得都懂。\r\n\r\n说一说腾讯云的 [Webbify](https://webify.cloudbase.net/)。今天 (2024年4月15) 上去想要部署一个新的站点,居然发现以前的 **"按量付费"** 计费模式已经消失,取而代之的是一个每月至少 15 块的购买时长模式。作为一个 2021 年就不再更新的产品,这样的收费模式真是让人瞬间欲望大减。\r\n![webify-price-15-pre-month.webp](https://static.weiyan.tech/2024/04/webify-price-15-pre-month.webp)\r\n\r\n回过头来看一看国外的 [Netlify](https://app.netlify.com/)、[Vercel](https://vercel.com/)、[Cloudflare Pages](https://www.cloudflare-cn.com/developer-platform/pages/),甚至是 GitHub Pages,再看一下国内的这些平台,真是一言难尽,除了先培养用户再收割,好像也没剩下什么了。\r\n', 'bodyText': 'Gitee Pages 由于审查原因,基本上已经是名存实亡的状态了;之前勉强可以使用的 Webbify 现如今也变成了每月至少 15 块的购买时长模式。\n\n之前在《越来越难用的国内代码托管平台》吐槽过一波国内所谓开源平台的状况,今天又发现除了代码平台外,原来静态部署的平台也走上了这一条路。\nGitee Pages 就不说了,懂得都懂。\n说一说腾讯云的 Webbify。今天 (2024年4月15) 上去想要部署一个新的站点,居然发现以前的 "按量付费" 计费模式已经消失,取而代之的是一个每月至少 15 块的购买时长模式。作为一个 2021 年就不再更新的产品,这样的收费模式真是让人瞬间欲望大减。\n\n回过头来看一看国外的 Netlify、Vercel、Cloudflare Pages,甚至是 GitHub Pages,再看一下国内的这些平台,真是一言难尽,除了先培养用户再收割,好像也没剩下什么了。', 'bodyHTML': '

Gitee Pages 由于审查原因,基本上已经是名存实亡的状态了;之前勉强可以使用的 Webbify 现如今也变成了每月至少 15 块的购买时长模式。

\n\n

之前在《越来越难用的国内代码托管平台》吐槽过一波国内所谓开源平台的状况,今天又发现除了代码平台外,原来静态部署的平台也走上了这一条路。

\n

Gitee Pages 就不说了,懂得都懂。

\n

说一说腾讯云的 Webbify。今天 (2024年4月15) 上去想要部署一个新的站点,居然发现以前的 "按量付费" 计费模式已经消失,取而代之的是一个每月至少 15 块的购买时长模式。作为一个 2021 年就不再更新的产品,这样的收费模式真是让人瞬间欲望大减。
\nwebify-price-15-pre-month.webp

\n

回过头来看一看国外的 NetlifyVercelCloudflare Pages,甚至是 GitHub Pages,再看一下国内的这些平台,真是一言难尽,除了先培养用户再收割,好像也没剩下什么了。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '备案接入信息与实际接入信息不符', 'number': 66, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/66', 'createdAt': '2024-04-11T07:09:00Z', 'lastEditedAt': '2024-04-11T07:11:25Z', 'updatedAt': '2024-04-11T07:11:25Z', 'body': '在阿里云注册且完成备案的域名,前两天收到了信息:如您的网站备案还要继续使用,请您务必于2024-04-18 09:05:39之前设置解析指向阿里云内地服务器且恢复该网站在阿里云内地节点服务器的正常访问。\r\n\r\n\r\n\r\n> 如您的网站备案还要继续使用,请您务必于2024-04-18 09:05:39之前设置解析指向阿里云内地服务器且恢复该网站在阿里云内地节点服务器的正常访问。若在规定时间内未完成整改,可能会导致备案信息被取消接入或被注销,影响您网站的正常访问;若您的备案域名解析IP地址已指向阿里云备案的内地节点(不含香港)服务器,且保持正常访问,请忽略此邮件。\r\n\r\n![beian-weiyan-cc.webp](https://static.weiyan.tech/2024/04/beian-weiyan-cc.webp)\r\n\r\n目前,参考知乎《[阿里云服务器备案域名会掉吗](https://zhuanlan.zhihu.com/p/516077564)》的方法 —— 先把目前 `weiyan.cc` 下的一到两个子域名增加一个 A 记录绑定到阿里云的 ECS 公网 IP,主域名继续按目前的要求通过 CNAME 绑定 [weiyan.netlify.app](https://weiyan.netlify.app)。\r\n\r\n再看看后续是否有影响。', 'bodyText': '在阿里云注册且完成备案的域名,前两天收到了信息:如您的网站备案还要继续使用,请您务必于2024-04-18 09:05:39之前设置解析指向阿里云内地服务器且恢复该网站在阿里云内地节点服务器的正常访问。\n\n\n如您的网站备案还要继续使用,请您务必于2024-04-18 09:05:39之前设置解析指向阿里云内地服务器且恢复该网站在阿里云内地节点服务器的正常访问。若在规定时间内未完成整改,可能会导致备案信息被取消接入或被注销,影响您网站的正常访问;若您的备案域名解析IP地址已指向阿里云备案的内地节点(不含香港)服务器,且保持正常访问,请忽略此邮件。\n\n\n目前,参考知乎《阿里云服务器备案域名会掉吗》的方法 —— 先把目前 weiyan.cc 下的一到两个子域名增加一个 A 记录绑定到阿里云的 ECS 公网 IP,主域名继续按目前的要求通过 CNAME 绑定 weiyan.netlify.app。\n再看看后续是否有影响。', 'bodyHTML': '

在阿里云注册且完成备案的域名,前两天收到了信息:如您的网站备案还要继续使用,请您务必于2024-04-18 09:05:39之前设置解析指向阿里云内地服务器且恢复该网站在阿里云内地节点服务器的正常访问。

\n\n
\n

如您的网站备案还要继续使用,请您务必于2024-04-18 09:05:39之前设置解析指向阿里云内地服务器且恢复该网站在阿里云内地节点服务器的正常访问。若在规定时间内未完成整改,可能会导致备案信息被取消接入或被注销,影响您网站的正常访问;若您的备案域名解析IP地址已指向阿里云备案的内地节点(不含香港)服务器,且保持正常访问,请忽略此邮件。

\n
\n

beian-weiyan-cc.webp

\n

目前,参考知乎《阿里云服务器备案域名会掉吗》的方法 —— 先把目前 weiyan.cc 下的一到两个子域名增加一个 A 记录绑定到阿里云的 ECS 公网 IP,主域名继续按目前的要求通过 CNAME 绑定 weiyan.netlify.app

\n

再看看后续是否有影响。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'RSS 订阅插件 mkdocs-rss-plugin 的一些问题', 'number': 65, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/65', 'createdAt': '2024-04-11T02:37:00Z', 'lastEditedAt': None, 'updatedAt': '2024-04-22T01:31:54Z', 'body': '聊一下 Mkdocs Material 的默认插件 [mkdocs-rss-plugin](https://github.com/Guts/mkdocs-rss-plugin) 在使用上的一些问题。\r\n\r\n\r\n\r\n对于 blog 插件,默认的 RSS 里边提供的地址有一部分会默认为目录链接(例如 `category` 和 `archive`),而非文章地址。\r\n\r\n![rss-item.webp](https://static.weiyan.tech/2024/04/rss-item.webp)\r\n\r\n针对这一种情况,需要使用 RSS 配置的 [`match_path`](https://guts.github.io/mkdocs-rss-plugin/configuration/#match_path-filter-pages-to-include-in-feed),即可解决:\r\n\r\n```\r\nplugins:\r\n - rss:\r\n match_path: "(blog/posts|flinks|galaxy|message|note|readme|tech|yuque)/.*"\r\n date_from_meta:\r\n as_creation: date\r\n categories:\r\n - categories\r\n - tags\r\n```\r\n', 'bodyText': '聊一下 Mkdocs Material 的默认插件 mkdocs-rss-plugin 在使用上的一些问题。\n\n对于 blog 插件,默认的 RSS 里边提供的地址有一部分会默认为目录链接(例如 category 和 archive),而非文章地址。\n\n针对这一种情况,需要使用 RSS 配置的 match_path,即可解决:\nplugins:\n - rss:\n match_path: "(blog/posts|flinks|galaxy|message|note|readme|tech|yuque)/.*"\n date_from_meta:\n as_creation: date\n categories:\n - categories\n - tags', 'bodyHTML': '

聊一下 Mkdocs Material 的默认插件 mkdocs-rss-plugin 在使用上的一些问题。

\n\n

对于 blog 插件,默认的 RSS 里边提供的地址有一部分会默认为目录链接(例如 categoryarchive),而非文章地址。

\n

rss-item.webp

\n

针对这一种情况,需要使用 RSS 配置的 match_path,即可解决:

\n
plugins:\n  - rss:\n      match_path: "(blog/posts|flinks|galaxy|message|note|readme|tech|yuque)/.*"\n      date_from_meta:\n        as_creation: date\n      categories:\n        - categories\n        - tags\n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': [{'name': 'mkdocs'}]}, 'comments': {'nodes': [{'body': '终于修复了,之前一直有问题。', 'author': {'login': 'Jaaayden'}}]}}, {'title': '无趣的人', 'number': 64, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/64', 'createdAt': '2024-04-07T07:29:06Z', 'lastEditedAt': None, 'updatedAt': '2024-04-07T07:29:07Z', 'body': '有趣的灵魂万里挑一,好看的皮囊千篇一律。\r\n\r\n\r\n\r\n活得通透的人 ,没有特别想维持的关系 ,也没有特别想要的东西 ,走近的人不抗拒 ,离开的人不强留 ,就连吃亏也懒得计较。\r\n\r\n从统计上来看,成年后还能重塑自我的人太罕见了。年纪越大就越相信命运,其中最大的一个原因就是理解人的改变之难。意图改变不如早早学会接纳。', 'bodyText': '有趣的灵魂万里挑一,好看的皮囊千篇一律。\n\n活得通透的人 ,没有特别想维持的关系 ,也没有特别想要的东西 ,走近的人不抗拒 ,离开的人不强留 ,就连吃亏也懒得计较。\n从统计上来看,成年后还能重塑自我的人太罕见了。年纪越大就越相信命运,其中最大的一个原因就是理解人的改变之难。意图改变不如早早学会接纳。', 'bodyHTML': '

有趣的灵魂万里挑一,好看的皮囊千篇一律。

\n\n

活得通透的人 ,没有特别想维持的关系 ,也没有特别想要的东西 ,走近的人不抗拒 ,离开的人不强留 ,就连吃亏也懒得计较。

\n

从统计上来看,成年后还能重塑自我的人太罕见了。年纪越大就越相信命运,其中最大的一个原因就是理解人的改变之难。意图改变不如早早学会接纳。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '腾讯云 cos 也被盗刷了', 'number': 63, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/63', 'createdAt': '2024-03-29T07:07:37Z', 'lastEditedAt': '2024-04-03T01:31:55Z', 'updatedAt': '2024-04-03T01:31:56Z', 'body': '我的 [WebStack-Hugo](https://bioit.top/) 个人导航站点最开始用的是腾讯云的 cos 对象存储作为所有图片的存储和访问,在 2024 年 3 月底的时候收到腾讯云的通知说 200 万次的标准存储请求已经用掉了 180 多万次。\r\n\r\n\r\n\r\n![cos-warning.webp](https://static.weiyan.tech/2024/03/cos-warning.webp)\r\n\r\n收到信息吓了一跳,心想我这一个小破网站不至于这么多的请求吧,肯定被攻击盗刷了。加上之前在网络上看到的阿里云/腾讯云对象存储被刷爆的新闻还历历在目,于是赶紧的上去腾讯云一看发现一天的读写请求居然达到了 25 万多次!\r\n\r\n![cos-y-requests](https://static.weiyan.tech/2024/03/cos-y-requests.webp)\r\n\r\n虽然之前一直设置了防盗链,但是一直允许着 **"空 referer"**,这无疑是一个巨大的漏洞,参考 《[COS被流量盗刷了](https://zhuanlan.zhihu.com/p/660308000)》 的经历,第一时间就把这个 **"空 referer"** 设置为了 **"拒绝"**,并开启了日志。\r\n\r\n果不其然,一段时间过后从生成的日志文件,发现了这样的一个网址:。\r\n![123-wqydl-get](https://static.weiyan.tech/2024/03/123-wqydl-get.webp)\r\n\r\n这个网站一直在请求获取个人 cos 内的 `/webstack/logos/default.webp` 这个图片!为了安全起见,又赶紧第一时间把这个网站加入了黑名单,并且把对应的 cos 权限设置成了 **"私有读写"**。\r\n\r\n但是从源源不断产生的日志可以看到这个恶心的网站还一直不依不饶在每隔几分钟就执行一堆读取请求!\r\n![get-requests-by-time.webp](https://static.weiyan.tech/2024/03/get-requests-by-time.webp)\r\n\r\n但幸运的是这些请求现在都 **"AccessDenied"** 了,但对它的一些后续可能的动作也很是好奇,在持续观察中。\r\n![cos-access-denied.webp](https://static.weiyan.tech/2024/03/cos-access-denied.webp)\r\n\r\n![cos-log.png](https://static.weiyan.tech/2024/03/cos-log.png)\r\n\r\n![cos-safe.png](https://static.weiyan.tech/2024/03/cos-safe.png)\r\n\r\n终于,第二天的晚上终于在他们的官网联系上了对应的客服,他们把相应的网站停掉后一切又回归正常。 \r\n![cos-package-free.webp](https://static.weiyan.tech/2024/04/cos-package-free.webp)\r\n\r\n最后,以此为鉴,希望大家在提供公共资源的时候擦亮眼睛,避免踩坑。', 'bodyText': '我的 WebStack-Hugo 个人导航站点最开始用的是腾讯云的 cos 对象存储作为所有图片的存储和访问,在 2024 年 3 月底的时候收到腾讯云的通知说 200 万次的标准存储请求已经用掉了 180 多万次。\n\n\n收到信息吓了一跳,心想我这一个小破网站不至于这么多的请求吧,肯定被攻击盗刷了。加上之前在网络上看到的阿里云/腾讯云对象存储被刷爆的新闻还历历在目,于是赶紧的上去腾讯云一看发现一天的读写请求居然达到了 25 万多次!\n\n虽然之前一直设置了防盗链,但是一直允许着 "空 referer",这无疑是一个巨大的漏洞,参考 《COS被流量盗刷了》 的经历,第一时间就把这个 "空 referer" 设置为了 "拒绝",并开启了日志。\n果不其然,一段时间过后从生成的日志文件,发现了这样的一个网址:https://123.wqydl.cn/。\n\n这个网站一直在请求获取个人 cos 内的 /webstack/logos/default.webp 这个图片!为了安全起见,又赶紧第一时间把这个网站加入了黑名单,并且把对应的 cos 权限设置成了 "私有读写"。\n但是从源源不断产生的日志可以看到这个恶心的网站还一直不依不饶在每隔几分钟就执行一堆读取请求!\n\n但幸运的是这些请求现在都 "AccessDenied" 了,但对它的一些后续可能的动作也很是好奇,在持续观察中。\n\n\n\n终于,第二天的晚上终于在他们的官网联系上了对应的客服,他们把相应的网站停掉后一切又回归正常。\n\n最后,以此为鉴,希望大家在提供公共资源的时候擦亮眼睛,避免踩坑。', 'bodyHTML': '

我的 WebStack-Hugo 个人导航站点最开始用的是腾讯云的 cos 对象存储作为所有图片的存储和访问,在 2024 年 3 月底的时候收到腾讯云的通知说 200 万次的标准存储请求已经用掉了 180 多万次。

\n\n

cos-warning.webp

\n

收到信息吓了一跳,心想我这一个小破网站不至于这么多的请求吧,肯定被攻击盗刷了。加上之前在网络上看到的阿里云/腾讯云对象存储被刷爆的新闻还历历在目,于是赶紧的上去腾讯云一看发现一天的读写请求居然达到了 25 万多次!

\n

cos-y-requests

\n

虽然之前一直设置了防盗链,但是一直允许着 "空 referer",这无疑是一个巨大的漏洞,参考 《COS被流量盗刷了》 的经历,第一时间就把这个 "空 referer" 设置为了 "拒绝",并开启了日志。

\n

果不其然,一段时间过后从生成的日志文件,发现了这样的一个网址:https://123.wqydl.cn/
\n123-wqydl-get

\n

这个网站一直在请求获取个人 cos 内的 /webstack/logos/default.webp 这个图片!为了安全起见,又赶紧第一时间把这个网站加入了黑名单,并且把对应的 cos 权限设置成了 "私有读写"

\n

但是从源源不断产生的日志可以看到这个恶心的网站还一直不依不饶在每隔几分钟就执行一堆读取请求!
\nget-requests-by-time.webp

\n

但幸运的是这些请求现在都 "AccessDenied" 了,但对它的一些后续可能的动作也很是好奇,在持续观察中。
\ncos-access-denied.webp

\n

cos-log.png

\n

cos-safe.png

\n

终于,第二天的晚上终于在他们的官网联系上了对应的客服,他们把相应的网站停掉后一切又回归正常。
\ncos-package-free.webp

\n

最后,以此为鉴,希望大家在提供公共资源的时候擦亮眼睛,避免踩坑。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '图床管理与使用', 'number': 62, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/62', 'createdAt': '2024-03-27T07:48:45Z', 'lastEditedAt': '2024-03-28T05:02:32Z', 'updatedAt': '2024-03-28T05:02:32Z', 'body': '随着博客和其他一些站点多了起来,日积月累的访问越来越觉得腾讯云 cos 和阿里云 oss 是远远不够的,于是开始想着寻找可以一劳永逸的图床管理和使用替代者。\r\n\r\n\r\n\r\nGitHub 的图床虽然不错,但如果文件越来越多,终究不是一个很好的解决方案。\r\n\r\nCloudflare R2 目前看来是个不错的选项,但是图片的上传、删除和日常管理目前还没有找到一个比较顺手的工具。目前在用的一个 [Picx4R2](https://github.com/shenweiyan/Picx4R2/) 还有一些不太满意的地方,即上传的图片无法保留原始的文件名!—— 不过幸运的是借助百度文心一言终于把保留原始文件名的这个问题给解决了。', 'bodyText': '随着博客和其他一些站点多了起来,日积月累的访问越来越觉得腾讯云 cos 和阿里云 oss 是远远不够的,于是开始想着寻找可以一劳永逸的图床管理和使用替代者。\n\nGitHub 的图床虽然不错,但如果文件越来越多,终究不是一个很好的解决方案。\nCloudflare R2 目前看来是个不错的选项,但是图片的上传、删除和日常管理目前还没有找到一个比较顺手的工具。目前在用的一个 Picx4R2 还有一些不太满意的地方,即上传的图片无法保留原始的文件名!—— 不过幸运的是借助百度文心一言终于把保留原始文件名的这个问题给解决了。', 'bodyHTML': '

随着博客和其他一些站点多了起来,日积月累的访问越来越觉得腾讯云 cos 和阿里云 oss 是远远不够的,于是开始想着寻找可以一劳永逸的图床管理和使用替代者。

\n\n

GitHub 的图床虽然不错,但如果文件越来越多,终究不是一个很好的解决方案。

\n

Cloudflare R2 目前看来是个不错的选项,但是图片的上传、删除和日常管理目前还没有找到一个比较顺手的工具。目前在用的一个 Picx4R2 还有一些不太满意的地方,即上传的图片无法保留原始的文件名!—— 不过幸运的是借助百度文心一言终于把保留原始文件名的这个问题给解决了。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'Python 里面没 if 也能用 else', 'number': 61, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/61', 'createdAt': '2024-03-21T01:47:26Z', 'lastEditedAt': '2024-03-22T01:21:34Z', 'updatedAt': '2024-03-22T01:21:34Z', 'body': '> 这是来自于 [Yang Zhou](https://twitter.com/YangZhou1993) 发表在 [Medium](https://medium.com/techtofreedom/beyond-if-else-leveraging-pythons-versatile-else-statements-9ac260dac102) 的一篇文章 《[Beyond If-Else: Leveraging Python’s Versatile “Else” Statements](https://medium.com/techtofreedom/beyond-if-else-leveraging-pythons-versatile-else-statements-9ac260dac102)》,作者觉得挺有意思的,拿过来简单翻译了一下在这里分享给大家。\r\n\r\n\r\n\r\n当我们说到 "else",必须先有 "if"。\r\n\r\n这对于许多编程语言来说都是正确的,但对于 Python 来说却不然。\r\n\r\nPython 的 else 语句比我们想象的更通用。\r\n\r\n从循环后的 "else" 到 try- except 块后的 "else",本文将探讨 else 语句鲜为人知的功能。\r\n\r\n我们不一定需要在生产中使用这些技巧,尤其是当我们的同事还不知道它们时,但仅仅意识到它们的存在就可以让我们再次感受到 Python 的灵活性和多功能性。\r\n\r\n## 1. While-Else 结构\r\n\r\n在 Python 中, `while` 循环可以与 `else` 块配对。当且仅当循环正常完成时,`else` 块才会执行,这意味着它不会通过 `break` 语句终止。\r\n\r\n换句话说,如果 `while` 循环被 `break` 终止,则 `else` 块将不会被执行。\r\n```python\r\nleaders = ["Elon", "Tim", "Warren"]\r\ni = 0\r\nwhile i < len(leaders):\r\n if leaders[i] == "Yang":\r\n print("Yang is a leader!")\r\n break\r\n i += 1\r\nelse:\r\n print("Not found Yang!")\r\n\r\n# Not found Yang!\r\n```\r\n\r\n如上面的示例所示, `while` 循环迭代 `leaders` 列表,搜索领导者 "Yang"。不幸的是,"Yang" 并不是该名单中真正的领导者。所以 `break` 语句没有被执行。因此,`else` 语句下的代码就被执行了。\r\n\r\n`else` 语句的这种意外用法使我们无需添加额外的标志变量来标记循环是否被破坏。这样我们的 Python 程序就可以精简一些了。\r\n\r\n## 2. 带有 For 循环的 Else 语句\r\n\r\nFor 循环和 `while` 循环是编程的孪生兄弟。如果我们可以在 while 循环中利用 else 语句的多功能性,那么毫无疑问它可以用于 for 循环。\r\n\r\n这个想法是完全相同的: \r\n\r\n> The "else" block only executes when there is no break in the for loop. \r\n> "else" 块仅在 for 循环中没有中断时执行。 \r\n\r\n让我们用 for 循环重写前面的示例:\r\n```python\r\nleaders = ["Elon", "Tim", "Warren"]\r\n\r\nfor i in leaders:\r\n if i == "Yang":\r\n print("Yang is a leader!")\r\n break\r\nelse:\r\n print("Not found Yang!")\r\n\r\n# Not found Yang!\r\n```\r\n\r\n代码更简洁了,不是吗?你能用其他编程语言做到这一点吗?\r\n\r\n## 3. 使用 Else 语句进行异常处理\r\n\r\n异常处理是编写健壮且无错误的代码的一项重要技术。\r\n\r\n在 Python 中,整个异常处理代码块的结构应该如下:\r\n```python\r\ntry:\r\n # Code that might raise an exception\r\nexcept SomeException:\r\n # Code that runs if the try block raised \'SomeException\'\r\nelse:\r\n # Code that runs if the try block did NOT raise any exceptions\r\nfinally:\r\n # Code that always runs no matter what, often for cleanup\r\n```\r\n\r\n除了 `try` 块之外,所有其他部分都是可选的。\r\n\r\n当 `try` 块未引发异常时, `else` 块就会执行。这是放置仅当 `try` 块成功且无异常时才运行的代码的好地方。这对于阐明代码的意图并防止 `except` 块意外捕获非常有用。\r\n\r\n例如,以下程序实现了一个非常简单的除法函数:\r\n```python\r\ndef divide(x, y):\r\n try:\r\n result = x / y\r\n except ZeroDivisionError:\r\n print("Error: Division by zero.")\r\n else:\r\n print(f"Result is {result}")\r\n finally:\r\n print("Executing finally clause.")\r\n```\r\n\r\n如果没有遇到 `ZeroDivisionError`,结果如下:\r\n\r\n```python\r\ndivide(2077, 1)\r\n# Result is 2077.0\r\n# Executing finally clause.\r\n```\r\n\r\n当然,如果满足定义的异常,则会打印相关的 `Error` 消息:\r\n```python\r\ndivide(2077, 0)\r\n# Error: Division by zero.\r\n# Executing finally clause.\r\n```\r\n\r\n## 要点总结\r\n\r\n在 Python 中,else 语句不一定位于 if 语句之后。\r\n\r\n它还有三个额外但鲜为人知的用途: \r\n\r\n- while-else 循环 \r\n- for-else 循环 \r\n- 使用 else 块进行异常处理 \r\n\r\n但是,我不建议您在生产中频繁应用它们,因为使用鲜为人知的功能可能会降低可读性并使您的同事感到困惑。但理解并随意应用它们会给你的同事留下深刻的印象,并巩固你作为 "Python 大师" 的地位。 😎', 'bodyText': '这是来自于 Yang Zhou 发表在 Medium 的一篇文章 《Beyond If-Else: Leveraging Python’s Versatile “Else” Statements》,作者觉得挺有意思的,拿过来简单翻译了一下在这里分享给大家。\n\n\n当我们说到 "else",必须先有 "if"。\n这对于许多编程语言来说都是正确的,但对于 Python 来说却不然。\nPython 的 else 语句比我们想象的更通用。\n从循环后的 "else" 到 try- except 块后的 "else",本文将探讨 else 语句鲜为人知的功能。\n我们不一定需要在生产中使用这些技巧,尤其是当我们的同事还不知道它们时,但仅仅意识到它们的存在就可以让我们再次感受到 Python 的灵活性和多功能性。\n1. While-Else 结构\n在 Python 中, while 循环可以与 else 块配对。当且仅当循环正常完成时,else 块才会执行,这意味着它不会通过 break 语句终止。\n换句话说,如果 while 循环被 break 终止,则 else 块将不会被执行。\nleaders = ["Elon", "Tim", "Warren"]\ni = 0\nwhile i < len(leaders):\n if leaders[i] == "Yang":\n print("Yang is a leader!")\n break\n i += 1\nelse:\n print("Not found Yang!")\n\n# Not found Yang!\n如上面的示例所示, while 循环迭代 leaders 列表,搜索领导者 "Yang"。不幸的是,"Yang" 并不是该名单中真正的领导者。所以 break 语句没有被执行。因此,else 语句下的代码就被执行了。\nelse 语句的这种意外用法使我们无需添加额外的标志变量来标记循环是否被破坏。这样我们的 Python 程序就可以精简一些了。\n2. 带有 For 循环的 Else 语句\nFor 循环和 while 循环是编程的孪生兄弟。如果我们可以在 while 循环中利用 else 语句的多功能性,那么毫无疑问它可以用于 for 循环。\n这个想法是完全相同的:\n\nThe "else" block only executes when there is no break in the for loop.\n"else" 块仅在 for 循环中没有中断时执行。\n\n让我们用 for 循环重写前面的示例:\nleaders = ["Elon", "Tim", "Warren"]\n\nfor i in leaders:\n if i == "Yang":\n print("Yang is a leader!")\n break\nelse:\n print("Not found Yang!")\n\n# Not found Yang!\n代码更简洁了,不是吗?你能用其他编程语言做到这一点吗?\n3. 使用 Else 语句进行异常处理\n异常处理是编写健壮且无错误的代码的一项重要技术。\n在 Python 中,整个异常处理代码块的结构应该如下:\ntry:\n # Code that might raise an exception\nexcept SomeException:\n # Code that runs if the try block raised \'SomeException\'\nelse:\n # Code that runs if the try block did NOT raise any exceptions\nfinally:\n # Code that always runs no matter what, often for cleanup\n除了 try 块之外,所有其他部分都是可选的。\n当 try 块未引发异常时, else 块就会执行。这是放置仅当 try 块成功且无异常时才运行的代码的好地方。这对于阐明代码的意图并防止 except 块意外捕获非常有用。\n例如,以下程序实现了一个非常简单的除法函数:\ndef divide(x, y):\n try:\n result = x / y\n except ZeroDivisionError:\n print("Error: Division by zero.")\n else:\n print(f"Result is {result}")\n finally:\n print("Executing finally clause.")\n如果没有遇到 ZeroDivisionError,结果如下:\ndivide(2077, 1)\n# Result is 2077.0\n# Executing finally clause.\n当然,如果满足定义的异常,则会打印相关的 Error 消息:\ndivide(2077, 0)\n# Error: Division by zero.\n# Executing finally clause.\n要点总结\n在 Python 中,else 语句不一定位于 if 语句之后。\n它还有三个额外但鲜为人知的用途:\n\nwhile-else 循环\nfor-else 循环\n使用 else 块进行异常处理\n\n但是,我不建议您在生产中频繁应用它们,因为使用鲜为人知的功能可能会降低可读性并使您的同事感到困惑。但理解并随意应用它们会给你的同事留下深刻的印象,并巩固你作为 "Python 大师" 的地位。 😎', 'bodyHTML': '
\n

这是来自于 Yang Zhou 发表在 Medium 的一篇文章 《Beyond If-Else: Leveraging Python’s Versatile “Else” Statements》,作者觉得挺有意思的,拿过来简单翻译了一下在这里分享给大家。

\n
\n\n

当我们说到 "else",必须先有 "if"。

\n

这对于许多编程语言来说都是正确的,但对于 Python 来说却不然。

\n

Python 的 else 语句比我们想象的更通用。

\n

从循环后的 "else" 到 try- except 块后的 "else",本文将探讨 else 语句鲜为人知的功能。

\n

我们不一定需要在生产中使用这些技巧,尤其是当我们的同事还不知道它们时,但仅仅意识到它们的存在就可以让我们再次感受到 Python 的灵活性和多功能性。

\n

1. While-Else 结构

\n

在 Python 中, while 循环可以与 else 块配对。当且仅当循环正常完成时,else 块才会执行,这意味着它不会通过 break 语句终止。

\n

换句话说,如果 while 循环被 break 终止,则 else 块将不会被执行。

\n
leaders = ["Elon", "Tim", "Warren"]\ni = 0\nwhile i < len(leaders):\n    if leaders[i] == "Yang":\n        print("Yang is a leader!")\n        break\n    i += 1\nelse:\n    print("Not found Yang!")\n\n# Not found Yang!
\n

如上面的示例所示, while 循环迭代 leaders 列表,搜索领导者 "Yang"。不幸的是,"Yang" 并不是该名单中真正的领导者。所以 break 语句没有被执行。因此,else 语句下的代码就被执行了。

\n

else 语句的这种意外用法使我们无需添加额外的标志变量来标记循环是否被破坏。这样我们的 Python 程序就可以精简一些了。

\n

2. 带有 For 循环的 Else 语句

\n

For 循环和 while 循环是编程的孪生兄弟。如果我们可以在 while 循环中利用 else 语句的多功能性,那么毫无疑问它可以用于 for 循环。

\n

这个想法是完全相同的:

\n
\n

The "else" block only executes when there is no break in the for loop.
\n"else" 块仅在 for 循环中没有中断时执行。

\n
\n

让我们用 for 循环重写前面的示例:

\n
leaders = ["Elon", "Tim", "Warren"]\n\nfor i in leaders:\n    if i == "Yang":\n        print("Yang is a leader!")\n        break\nelse:\n    print("Not found Yang!")\n\n# Not found Yang!
\n

代码更简洁了,不是吗?你能用其他编程语言做到这一点吗?

\n

3. 使用 Else 语句进行异常处理

\n

异常处理是编写健壮且无错误的代码的一项重要技术。

\n

在 Python 中,整个异常处理代码块的结构应该如下:

\n
try:\n    # Code that might raise an exception\nexcept SomeException:\n    # Code that runs if the try block raised \'SomeException\'\nelse:\n    # Code that runs if the try block did NOT raise any exceptions\nfinally:\n    # Code that always runs no matter what, often for cleanup
\n

除了 try 块之外,所有其他部分都是可选的。

\n

try 块未引发异常时, else 块就会执行。这是放置仅当 try 块成功且无异常时才运行的代码的好地方。这对于阐明代码的意图并防止 except 块意外捕获非常有用。

\n

例如,以下程序实现了一个非常简单的除法函数:

\n
def divide(x, y):\n    try:\n        result = x / y\n    except ZeroDivisionError:\n        print("Error: Division by zero.")\n    else:\n        print(f"Result is {result}")\n    finally:\n        print("Executing finally clause.")
\n

如果没有遇到 ZeroDivisionError,结果如下:

\n
divide(2077, 1)\n# Result is 2077.0\n# Executing finally clause.
\n

当然,如果满足定义的异常,则会打印相关的 Error 消息:

\n
divide(2077, 0)\n# Error: Division by zero.\n# Executing finally clause.
\n

要点总结

\n

在 Python 中,else 语句不一定位于 if 语句之后。

\n

它还有三个额外但鲜为人知的用途:

\n
    \n
  • while-else 循环
  • \n
  • for-else 循环
  • \n
  • 使用 else 块进行异常处理
  • \n
\n

但是,我不建议您在生产中频繁应用它们,因为使用鲜为人知的功能可能会降低可读性并使您的同事感到困惑。但理解并随意应用它们会给你的同事留下深刻的印象,并巩固你作为 "Python 大师" 的地位。 😎

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.2-编程'}, 'labels': {'nodes': [{'name': '翻译'}, {'name': '1.2.3-Python'}]}, 'comments': {'nodes': []}}, {'title': 'RockyLinux 9 基础配置与使用', 'number': 60, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/60', 'createdAt': '2024-03-08T02:24:12Z', 'lastEditedAt': '2024-10-31T02:14:48Z', 'updatedAt': '2024-10-31T02:14:48Z', 'body': '今天终于在阿里云入手了一台 2核(vCPU)+ 2GiB + 3Mbps 的 ECS,安装了最新的 Rocky Linux release 9.3 (Blue Onyx),记录一下开箱后的一些基础配置。\r\n\r\n\r\n\r\n![aliyun-99-plan](https://shub.weiyan.tech/kgarden/2024/03/aliyun-99-plan.png)\r\n\r\n## Hostname\r\n```\r\n[root@r0sasd1bQi ~]# hostnamectl # 查看一下当前主机名的情况\r\n[root@r0sasd1bQi ~]# hostnamectl set-hostname shen-server --static\r\n[root@r0sasd1bQi ~]# hostnamectl status\r\n[root@r0sasd1bQi ~]# reboot now # 重启服务器\r\n```\r\n\r\n## 创建新用户\r\n\r\n使用 `adduser` 命令将新用户添加到系统中:\r\n```bash\r\nadduser shenweiyan # 创建新用户\r\npasswd shenweiyan # 修改密码\r\n```\r\n\r\n## 用户添加超级权限\r\n\r\n把 `shenweiyan` 用户添加超级权限(`/etc/sudoers`):\r\n```\r\nshenweiyan ALL=(ALL) NOPASSWD: ALL\r\n```\r\n\r\n## 自定义快捷方式\r\n\r\n在 `~/.bashrc` 最后新增一下用户自定义的快捷方式。\r\n\r\n```\r\n# User Specific Alias\r\nalias disp=\'display\'\r\nalias rm=\'rm -i\'\r\nalias la=\'ls -al\'\r\nalias ll=\'ls -lh\'\r\nalias le=\'less -S\'\r\n\r\n# Custom History setting\r\n# HISTFILESIZE 定义了在 .bash_history 中保存命令的记录总数\r\nHISTFILESIZE=3000000\r\n# HISTSIZE 定义了 history 命令输出的记录数\r\nHISTSIZE=3000\r\n# 定义 History 输出格式\r\nexport HISTTIMEFORMAT=\'%F %T \'\r\n# 使用 HISTCONTROL 从命令历史中剔除连续重复的条目\r\nHISTCONTROL=ignoredups\r\n# 将 bash 内存中历史命令追加到 .bash_history 历史命令文件中, 默认只有退出 shell 是才会保存\r\nPROMPT_COMMAND="history -a"\r\n\r\n# Login Style\r\nPS1=\'\\033[35;1m\\u@\\h \\[\\e[m\\]\\t \\[\\033[36;1m\\]$(pwd) \\n$ \\[\\e[m\\]\'\r\nclear;\r\n```\r\n\r\n## epel-release\r\n\r\n> 企业版 Linux 附加软件包(Extra Packages for Enterprise Linux,以下简称 EPEL)是一个 Fedora 特别兴趣小组,用以创建、维护以及管理针对企业版 Linux 的一个高质量附加软件包集,面向的对象包括但不限于 [红帽企业版 Linux (RHEL)](https://fedoraproject.org/wiki/Red_Hat_Enterprise_Linux/zh-cn)、 CentOS、Scientific Linux (SL)、Oracle Linux (OL) 。\r\n> \r\n> 参考:[EPEL/zh-cn - Fedora Project Wiki](https://fedoraproject.org/wiki/EPEL/zh-cn)\r\n\r\n```bash\r\n# 下面两个命令都可以安装\r\nsudo dnf install epel-release\r\nsudo dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm\r\n```\r\n\r\n## Htop 和 Btop\r\n\r\n[Htop](https://htop.dev/) 是一个基于 C 编写的跨平台的交互式流程查看器,`htop` 是 `top` 的一个增强替代品,提供了更加友好的用户界面和更多的功能,相比系统自带的 `top` 更加直观好用。 \r\n\r\n```bash\r\nsudo dnf install htop\r\n```\r\n\r\n`btop` 也是一个改进版的 Linux top 命令,这个命令不仅列出了各种系统使用情况,包括内存、磁盘、网络和进程,而且还允许与鼠标互动。即使是在服务器安装上,你也可以在 `btop` 上指指点点,以树形方式查看进程,隐藏或显示某些显示,并访问选项菜单,在那里你可以调整显示的外观和感觉。\r\n```bash\r\nsudo dnf install btop\r\n```\r\n\r\n## Docker 安装与使用\r\n\r\n主要参考《[How To Install and Use Docker on Rocky Linux 9](https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-rocky-linux-9)》,具体步骤如下: \r\n\r\n- add the official Docker repository\r\n ```bash\r\n sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo\r\n ```\r\n\r\n- install Docker\r\n ```bash\r\n sudo dnf install docker-ce docker-ce-cli containerd.io\r\n ```\r\n\r\n- start the Docker daemon\r\n ```bash\r\n sudo systemctl start docker\r\n ```\r\n\r\n- Verify that it’s running\r\n ```bash\r\n sudo systemctl status docker\r\n ```\r\n ```\r\n Output\r\n ● docker.service - Docker Application Container Engine\r\n Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)\r\n Active: active (running) since Sun 2016-05-01 06:53:52 CDT; 1 weeks 3 days ago\r\n Docs: https://docs.docker.com\r\n Main PID: 749 (docker)\r\n ```\r\n\r\n- make sure it starts at every server reboot\r\n ```bash\r\n sudo systemctl enable docker\r\n ```\r\n\r\n- 配置非 root 用户使用 Docker\r\n ```bash\r\n sudo usermod -aG docker username\r\n newgrp docker #更新docker用户组\r\n ```', 'bodyText': '今天终于在阿里云入手了一台 2核(vCPU)+ 2GiB + 3Mbps 的 ECS,安装了最新的 Rocky Linux release 9.3 (Blue Onyx),记录一下开箱后的一些基础配置。\n\n\nHostname\n[root@r0sasd1bQi ~]# hostnamectl # 查看一下当前主机名的情况\n[root@r0sasd1bQi ~]# hostnamectl set-hostname shen-server --static\n[root@r0sasd1bQi ~]# hostnamectl status\n[root@r0sasd1bQi ~]# reboot now # 重启服务器\n\n创建新用户\n使用 adduser 命令将新用户添加到系统中:\nadduser shenweiyan # 创建新用户\npasswd shenweiyan # 修改密码\n用户添加超级权限\n把 shenweiyan 用户添加超级权限(/etc/sudoers):\nshenweiyan ALL=(ALL) NOPASSWD: ALL\n\n自定义快捷方式\n在 ~/.bashrc 最后新增一下用户自定义的快捷方式。\n# User Specific Alias\nalias disp=\'display\'\nalias rm=\'rm -i\'\nalias la=\'ls -al\'\nalias ll=\'ls -lh\'\nalias le=\'less -S\'\n\n# Custom History setting\n# HISTFILESIZE 定义了在 .bash_history 中保存命令的记录总数\nHISTFILESIZE=3000000\n# HISTSIZE 定义了 history 命令输出的记录数\nHISTSIZE=3000\n# 定义 History 输出格式\nexport HISTTIMEFORMAT=\'%F %T \'\n# 使用 HISTCONTROL 从命令历史中剔除连续重复的条目\nHISTCONTROL=ignoredups\n# 将 bash 内存中历史命令追加到 .bash_history 历史命令文件中, 默认只有退出 shell 是才会保存\nPROMPT_COMMAND="history -a"\n\n# Login Style\nPS1=\'\\033[35;1m\\u@\\h \\[\\e[m\\]\\t \\[\\033[36;1m\\]$(pwd) \\n$ \\[\\e[m\\]\'\nclear;\n\nepel-release\n\n企业版 Linux 附加软件包(Extra Packages for Enterprise Linux,以下简称 EPEL)是一个 Fedora 特别兴趣小组,用以创建、维护以及管理针对企业版 Linux 的一个高质量附加软件包集,面向的对象包括但不限于 红帽企业版 Linux (RHEL)、 CentOS、Scientific Linux (SL)、Oracle Linux (OL) 。\n参考:EPEL/zh-cn - Fedora Project Wiki\n\n# 下面两个命令都可以安装\nsudo dnf install epel-release\nsudo dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm\nHtop 和 Btop\nHtop 是一个基于 C 编写的跨平台的交互式流程查看器,htop 是 top 的一个增强替代品,提供了更加友好的用户界面和更多的功能,相比系统自带的 top 更加直观好用。\nsudo dnf install htop\nbtop 也是一个改进版的 Linux top 命令,这个命令不仅列出了各种系统使用情况,包括内存、磁盘、网络和进程,而且还允许与鼠标互动。即使是在服务器安装上,你也可以在 btop 上指指点点,以树形方式查看进程,隐藏或显示某些显示,并访问选项菜单,在那里你可以调整显示的外观和感觉。\nsudo dnf install btop\nDocker 安装与使用\n主要参考《How To Install and Use Docker on Rocky Linux 9》,具体步骤如下:\n\n\nadd the official Docker repository\nsudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo\n\n\ninstall Docker\nsudo dnf install docker-ce docker-ce-cli containerd.io\n\n\nstart the Docker daemon\nsudo systemctl start docker\n\n\nVerify that it’s running\nsudo systemctl status docker\nOutput\n● docker.service - Docker Application Container Engine\n Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)\n Active: active (running) since Sun 2016-05-01 06:53:52 CDT; 1 weeks 3 days ago\n Docs: https://docs.docker.com\n Main PID: 749 (docker)\n\n\n\nmake sure it starts at every server reboot\nsudo systemctl enable docker\n\n\n配置非 root 用户使用 Docker\nsudo usermod -aG docker username\nnewgrp docker #更新docker用户组', 'bodyHTML': '

今天终于在阿里云入手了一台 2核(vCPU)+ 2GiB + 3Mbps 的 ECS,安装了最新的 Rocky Linux release 9.3 (Blue Onyx),记录一下开箱后的一些基础配置。

\n\n

aliyun-99-plan

\n

Hostname

\n
[root@r0sasd1bQi ~]# hostnamectl   # 查看一下当前主机名的情况\n[root@r0sasd1bQi ~]# hostnamectl set-hostname shen-server --static\n[root@r0sasd1bQi ~]# hostnamectl status\n[root@r0sasd1bQi ~]# reboot now    # 重启服务器\n
\n

创建新用户

\n

使用 adduser 命令将新用户添加到系统中:

\n
adduser shenweiyan    # 创建新用户\npasswd shenweiyan     # 修改密码
\n

用户添加超级权限

\n

shenweiyan 用户添加超级权限(/etc/sudoers):

\n
shenweiyan      ALL=(ALL)       NOPASSWD: ALL\n
\n

自定义快捷方式

\n

~/.bashrc 最后新增一下用户自定义的快捷方式。

\n
# User Specific Alias\nalias disp=\'display\'\nalias rm=\'rm -i\'\nalias la=\'ls -al\'\nalias ll=\'ls -lh\'\nalias le=\'less -S\'\n\n# Custom History setting\n# HISTFILESIZE 定义了在 .bash_history 中保存命令的记录总数\nHISTFILESIZE=3000000\n# HISTSIZE 定义了 history 命令输出的记录数\nHISTSIZE=3000\n# 定义 History 输出格式\nexport HISTTIMEFORMAT=\'%F %T \'\n# 使用 HISTCONTROL 从命令历史中剔除连续重复的条目\nHISTCONTROL=ignoredups\n# 将 bash 内存中历史命令追加到 .bash_history 历史命令文件中, 默认只有退出 shell 是才会保存\nPROMPT_COMMAND="history -a"\n\n# Login Style\nPS1=\'\\033[35;1m\\u@\\h \\[\\e[m\\]\\t \\[\\033[36;1m\\]$(pwd) \\n$ \\[\\e[m\\]\'\nclear;\n
\n

epel-release

\n
\n

企业版 Linux 附加软件包(Extra Packages for Enterprise Linux,以下简称 EPEL)是一个 Fedora 特别兴趣小组,用以创建、维护以及管理针对企业版 Linux 的一个高质量附加软件包集,面向的对象包括但不限于 红帽企业版 Linux (RHEL)、 CentOS、Scientific Linux (SL)、Oracle Linux (OL) 。

\n

参考:EPEL/zh-cn - Fedora Project Wiki

\n
\n
# 下面两个命令都可以安装\nsudo dnf install epel-release\nsudo dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
\n

Htop 和 Btop

\n

Htop 是一个基于 C 编写的跨平台的交互式流程查看器,htoptop 的一个增强替代品,提供了更加友好的用户界面和更多的功能,相比系统自带的 top 更加直观好用。

\n
sudo dnf install htop
\n

btop 也是一个改进版的 Linux top 命令,这个命令不仅列出了各种系统使用情况,包括内存、磁盘、网络和进程,而且还允许与鼠标互动。即使是在服务器安装上,你也可以在 btop 上指指点点,以树形方式查看进程,隐藏或显示某些显示,并访问选项菜单,在那里你可以调整显示的外观和感觉。

\n
sudo dnf install btop
\n

Docker 安装与使用

\n

主要参考《How To Install and Use Docker on Rocky Linux 9》,具体步骤如下:

\n
    \n
  • \n

    add the official Docker repository

    \n
    sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
    \n
  • \n
  • \n

    install Docker

    \n
    sudo dnf install docker-ce docker-ce-cli containerd.io
    \n
  • \n
  • \n

    start the Docker daemon

    \n
    sudo systemctl start docker
    \n
  • \n
  • \n

    Verify that it’s running

    \n
    sudo systemctl status docker
    \n
    Output\n● docker.service - Docker Application Container Engine\n   Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)\n   Active: active (running) since Sun 2016-05-01 06:53:52 CDT; 1 weeks 3 days ago\n     Docs: https://docs.docker.com\n Main PID: 749 (docker)\n
    \n
  • \n
  • \n

    make sure it starts at every server reboot

    \n
    sudo systemctl enable docker
    \n
  • \n
  • \n

    配置非 root 用户使用 Docker

    \n
    sudo usermod -aG docker username\nnewgrp docker                     #更新docker用户组
    \n
  • \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '1.3.17-服务器配置使用'}]}, 'comments': {'nodes': []}}, {'title': '我的随笔和博客', 'number': 59, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/59', 'createdAt': '2024-03-04T01:27:09Z', 'lastEditedAt': None, 'updatedAt': '2024-03-04T01:27:10Z', 'body': '我的站点中把[随笔](https://weiyan.cc/note/)和[博客](https://weiyan.cc/blog/)分成了两个平行的导航,其实内容是一样的,只是原文托管的平台不一样而已。\r\n\r\n\r\n\r\n[随笔](https://weiyan.cc/note/) 的内容最开始是在语雀的[随笔与乱弹](https://www.yuque.com/shenweiyan/notebook)写的,导出来后加到现在的站点中,独立成了现在看到的[随笔](https://weiyan.cc/note/)。[博客](https://weiyan.cc/blog/) 则是从 2023 年起写在 [Knowledge-Garden](https://github.com/shenweiyan/Knowledge-Garden) 的 [discussions](https://github.com/shenweiyan/Knowledge-Garden/discussions/) 上的一些非技术相关杂文。', 'bodyText': '我的站点中把随笔和博客分成了两个平行的导航,其实内容是一样的,只是原文托管的平台不一样而已。\n\n随笔 的内容最开始是在语雀的随笔与乱弹写的,导出来后加到现在的站点中,独立成了现在看到的随笔。博客 则是从 2023 年起写在 Knowledge-Garden 的 discussions 上的一些非技术相关杂文。', 'bodyHTML': '

我的站点中把随笔博客分成了两个平行的导航,其实内容是一样的,只是原文托管的平台不一样而已。

\n\n

随笔 的内容最开始是在语雀的随笔与乱弹写的,导出来后加到现在的站点中,独立成了现在看到的随笔博客 则是从 2023 年起写在 Knowledge-Gardendiscussions 上的一些非技术相关杂文。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '如今迈步从头越', 'number': 58, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/58', 'createdAt': '2024-02-20T03:57:52Z', 'lastEditedAt': '2024-08-06T07:13:06Z', 'updatedAt': '2024-08-06T07:13:06Z', 'body': "2024 年应该是不太平凡的一年,农历新年后经历了很多的事情,生活也好工作也好,都不太平静。\r\n\r\n\r\n\r\n尤其对于工作而言,有一些更加深入的体会,明白很多人和事都并非表面那么简单。职场多年一路走来,曾经的迷茫不解,焦虑,纠结,吐槽,走到最后不由得越来越小心翼翼、如履薄冰。时间实际上是人的积极存在,它不仅是人的生命的尺度,而且是人的发展的空间。总的来说,更加要学会保护好自己,做事情多留点心,多一些思考。 \r\n美丽的林间公路风景\r\n\r\n人家说,能力也大,责任越大。对于个人职业和工作,更多的是权限越大,责任越大,任何的权限并非是越大越好。", 'bodyText': '2024 年应该是不太平凡的一年,农历新年后经历了很多的事情,生活也好工作也好,都不太平静。\n\n尤其对于工作而言,有一些更加深入的体会,明白很多人和事都并非表面那么简单。职场多年一路走来,曾经的迷茫不解,焦虑,纠结,吐槽,走到最后不由得越来越小心翼翼、如履薄冰。时间实际上是人的积极存在,它不仅是人的生命的尺度,而且是人的发展的空间。总的来说,更加要学会保护好自己,做事情多留点心,多一些思考。\n\n人家说,能力也大,责任越大。对于个人职业和工作,更多的是权限越大,责任越大,任何的权限并非是越大越好。', 'bodyHTML': '

2024 年应该是不太平凡的一年,农历新年后经历了很多的事情,生活也好工作也好,都不太平静。

\n\n

尤其对于工作而言,有一些更加深入的体会,明白很多人和事都并非表面那么简单。职场多年一路走来,曾经的迷茫不解,焦虑,纠结,吐槽,走到最后不由得越来越小心翼翼、如履薄冰。时间实际上是人的积极存在,它不仅是人的生命的尺度,而且是人的发展的空间。总的来说,更加要学会保护好自己,做事情多留点心,多一些思考。
\n美丽的林间公路风景

\n

人家说,能力也大,责任越大。对于个人职业和工作,更多的是权限越大,责任越大,任何的权限并非是越大越好。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '使用 Planemo 进行 Galaxy 工具开发', 'number': 57, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/57', 'createdAt': '2024-02-04T08:26:38Z', 'lastEditedAt': None, 'updatedAt': '2024-04-24T06:29:34Z', 'body': '> 说明:本文章原文发布于 《[使用 Planemo 进行 Galaxy 工具开发 - 语雀](https://www.yuque.com/shenweiyan/biox/planemo-for-galaxy)》,部分内容已更新。\r\n\r\n文章开始前,我们先了解一下 Planemo 到底是个什么东西。\r\n\r\n> Command-line utilities to assist in developing [Galaxy](http://galaxyproject.org/) and [Common Workflow Language](https://www.commonwl.org/) artifacts - including tools, workflows, and training materials.\r\n\r\n说白了,Planemo 就是用于 Galaxy 平台工具和 WDL 通用工作流语言相关产品辅助开发的一个命令行工具,这个程序集可以用于工具、流程,以及培训教材的开发。\r\n\r\n\r\n\r\n## 安装 Planemo \r\n\r\n无论是 pip 还是 conda 都可以安装 Planemo:\r\n```bash\r\n$ pip install planemo\r\n$ pip install -U git+git://github.com/galaxyproject/planemo.git\r\n```\r\n```bash\r\n$ conda config --add channels bioconda\r\n$ conda config --add channels conda-forge\r\n$ conda install planemo\r\n```\r\n\r\n接下来,进入今天的正题,我们来详细介绍一下怎么使用 Planemo 进行 Galaxy 工具开发。\r\n\r\n## 基础用法\r\n\r\n本指南将演示如何使用 Heng Li 的 `Seqtk` 软件包构建命令工具,该软件包用于处理 FASTA 和 FASTQ 文件中的序列数据。\r\n\r\n首先,我们需要先安装 `Seqtk` 。在这里,我们使用 `conda` 来安装 `Seqtk` (你也可以使用其他的方法安装)。\r\n```bash\r\n$ conda install --force --yes -c conda-forge -c bioconda seqtk=1.2\r\n ... seqtk installation ...\r\n$ seqtk seq\r\n Usage: seqtk seq [options] |\r\n Options: -q INT mask bases with quality lower than INT [0]\r\n -X INT mask bases with quality higher than INT [255]\r\n -n CHAR masked bases converted to CHAR; 0 for lowercase [0]\r\n -l INT number of residues per line; 0 for 2^32-1 [0]\r\n -Q INT quality shift: ASCII-INT gives base quality [33]\r\n -s INT random seed (effective with -f) [11]\r\n -f FLOAT sample FLOAT fraction of sequences [1]\r\n -M FILE mask regions in BED or name list FILE [null]\r\n -L INT drop sequences with length shorter than INT [0]\r\n -c mask complement region (effective with -M)\r\n -r reverse complement\r\n -A force FASTA output (discard quality)\r\n -C drop comments at the header lines\r\n -N drop sequences containing ambiguous bases\r\n -1 output the 2n-1 reads only\r\n -2 output the 2n reads only\r\n -V shift quality by \'(-Q) - 33\'\r\n```\r\n接下来,我们将下载一个 FASTQ 示例文件,并测试一个简单的 Seqtk 命令 `seq` ,该命令将 FASTQ 文件转换为 FASTA。\r\n```bash\r\n$ wget https://raw.githubusercontent.com/galaxyproject/galaxy-test-data/master/2.fastq\r\n$ seqtk seq -A 2.fastq > 2.fasta\r\n$ cat 2.fasta\r\n>EAS54_6_R1_2_1_413_324\r\nCCCTTCTTGTCTTCAGCGTTTCTCC\r\n>EAS54_6_R1_2_1_540_792\r\nTTGGCAGGCCAAGGCCGATGGATCA\r\n>EAS54_6_R1_2_1_443_348\r\nGTTGCTTCTGGCGTGGGTGGGGGGG\r\n```\r\n有关功能齐全的 Seqtk 包封装,可以在 GitHub 上查看 [Helena Rasche\'s wrappers](https://github.com/galaxyproject/tools-iuc/tree/master/tools/seqtk)。\r\n\r\nGalaxy 工具文件只是 XML 文件,因此此时可以打开文本编辑器并开始编写工具。Planemo 有一个命令 `tool_init` 可以快速生成一些样板 XML,因此首先开始。\r\n```bash\r\n$ planemo tool_init --id \'seqtk_seq\' --name \'Convert to FASTA (seqtk)\'\r\n```\r\n`tool_init` 命令可以采用各种复杂的参数,但如上面展示的 `--id` 和 `--name` 是其中两个最基本的参数。每个 Galaxy 工具都需要一个 ID(这是 Galaxy 自身用来标识该工具的简短标识符)和一个名称(此名称会显示给 Galaxy 用户,并且应该是该工具的简短描述)。工具名称可以包含空格,但其 ID 不能包含空格。\r\n\r\n上面的命令将生成一个 seqtk_seq.xml 文件,这个文件看起来像这样:\r\n```xml\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n\r\n```\r\n这个生成的模板 XML 文件具有了 Galaxy 工具所需的公共部分内容,但你仍然需要打开编辑器并填写命令模板、输入参数描述、工具输出信息、帮助部分信息等。\r\n\r\n`tool_init` 命令也可以做得更好。 们可以使用在 `seqtk seq -a 2.fastq> 2.fasta` 上面尝试过的测试命令作为示例,通过指定输入和输出来生成命令块,如下所示。\r\n```bash\r\n$ planemo tool_init --force \\\r\n --id \'seqtk_seq\' \\\r\n --name \'Convert to FASTA (seqtk)\' \\\r\n --requirement seqtk@1.2 \\\r\n --example_command \'seqtk seq -a 2.fastq > 2.fasta\' \\\r\n --example_input 2.fastq \\\r\n --example_output 2.fasta\r\n```\r\n这将生成以下 XML 文件- 该文件具有正确的输入和输出定义以及实际的命令模板。\r\n```xml\r\n\r\n \r\n seqtk\r\n \r\n \'$output1\'\r\n ]]>\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n(\r\n```\r\n如本节开头所示,命令 `seqtk seq` 会为 `seq` 命令生成帮助消息。 `tool_init` 可以获取该帮助消息,并使用 `help_from_command` 选项将其正确粘贴在生成的工具 XML 文件中。\r\n\r\n通常,命令帮助消息并不完全适用于工具,因为它们会提到参数名称和由工具抽象出来的类似细节,但它们可能是一个很好的起点。\r\n\r\n以下 Planemo 的 `tool_init` 的调用已增强为使用 `--help_from_command`。\r\n```bash\r\n$ planemo tool_init --force \\\r\n --id \'seqtk_seq\' \\\r\n --name \'Convert to FASTA (seqtk)\' \\\r\n --requirement seqtk@1.2 \\\r\n --example_command \'seqtk seq -a 2.fastq > 2.fasta\' \\\r\n --example_input 2.fastq \\\r\n --example_output 2.fasta \\\r\n --test_case \\\r\n --cite_url \'https://github.com/lh3/seqtk\' \\\r\n --help_from_command \'seqtk seq\'\r\n```\r\n\r\n除了演示 `--help_from_command` 之外,这还演示了使用 `--test_case` 从我们的示例生成测试用例并为基础工具添加引用。生成的工具 XML 文件为:\r\n```xml\r\n\r\n \r\n seqtk\r\n \r\n \'$output1\'\r\n ]]>\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n |\r\n\r\nOptions: -q INT mask bases with quality lower than INT [0]\r\n -X INT mask bases with quality higher than INT [255]\r\n -n CHAR masked bases converted to CHAR; 0 for lowercase [0]\r\n -l INT number of residues per line; 0 for 2^32-1 [0]\r\n -Q INT quality shift: ASCII-INT gives base quality [33]\r\n -s INT random seed (effective with -f) [11]\r\n -f FLOAT sample FLOAT fraction of sequences [1]\r\n -M FILE mask regions in BED or name list FILE [null]\r\n -L INT drop sequences with length shorter than INT [0]\r\n -c mask complement region (effective with -M)\r\n -r reverse complement\r\n -A force FASTA output (discard quality)\r\n -C drop comments at the header lines\r\n -N drop sequences containing ambiguous bases\r\n -1 output the 2n-1 reads only\r\n -2 output the 2n reads only\r\n -V shift quality by \'(-Q) - 33\'\r\n -U convert all bases to uppercases\r\n -S strip of white spaces in sequences\r\n\r\n\r\n ]]>\r\n \r\n \r\n@misc{githubseqtk,\r\n author = {LastTODO, FirstTODO},\r\n year = {TODO},\r\n title = {seqtk},\r\n publisher = {GitHub},\r\n journal = {GitHub repository},\r\n url = {https://github.com/lh3/seqtk},\r\n}\r\n \r\n\r\n```\r\n\r\n至此,我们有了一个功能相当齐全的 Galaxy 工具,它带有测试和帮助。这是一个非常简单的示例——通常,您需要在工具中投入更多工作才能实现这一点, `tool_init` 实际上只是为了让您入门而设计的。\r\n\r\n现在让我们检查并测试我们开发的工具。Planemo的 `lint`(或仅 `l` )命令将检查工具的 XML 有效性,检查是否有明显的错误以及是否符合 IUC 的最佳做法。\r\n```bash\r\n$ planemo l\r\nLinting tool /opt/galaxy/tools/seqtk_seq.xml\r\nApplying linter tests... CHECK\r\n.. CHECK: 1 test(s) found.\r\nApplying linter output... CHECK\r\n.. INFO: 1 outputs found.\r\nApplying linter inputs... CHECK\r\n.. INFO: Found 1 input parameters.\r\nApplying linter help... CHECK\r\n.. CHECK: Tool contains help section.\r\n.. CHECK: Help contains valid reStructuredText.\r\nApplying linter general... CHECK\r\n.. CHECK: Tool defines a version [0.1.0].\r\n.. CHECK: Tool defines a name [Convert to FASTA (seqtk)].\r\n.. CHECK: Tool defines an id [seqtk_seq].\r\n.. CHECK: Tool targets 16.01 Galaxy profile.\r\nApplying linter command... CHECK\r\n.. INFO: Tool contains a command.\r\nApplying linter citations... CHECK\r\n.. CHECK: Found 1 likely valid citations.\r\nApplying linter tool_xsd... CHECK\r\n.. INFO: File validates against XML schema.\r\n```\r\n默认情况下, `lint` 会在您当前的工作目录中找到所有工具,但是我们可以使用 `planemo lint seqtk_seq.xml` 指定一个特定的工具。\r\n\r\n接下来,我们可以使用 `test`(或仅执行 `t` )命令运行工具的功能测试。这将打印很多输出(因为它启动了 Galaxy 实例),但最终应该显示我们通过的一项测试。\r\n\r\n> 如果你的服务器已经安装了 Galaxy 实例,你可以编辑 ~/.planemo.yml 文件,指定 Galaxy 实例路径。\r\n\r\n```yaml\r\n## Specify a default galaxy_root for the `test` and `serve` commands here.\r\ngalaxy_root: /home/user/galaxy\r\n```\r\n> 完整的 `~/.planemo.yml` 示例,参考:[https://planemo.readthedocs.io/en/latest/configuration.html](https://planemo.readthedocs.io/en/latest/configuration.html)\r\n\r\n```bash\r\n$ planemo t\r\n...\r\nAll 1 test(s) executed passed.\r\nseqtk_seq[0]: passed\r\n```\r\n除了在控制台中将测试结果显示为红色(失败)或绿色(通过)外,Planemo 还默认为测试结果创建 HTML 报告。 还有更多测试报告选项可用,例如 `--test_output_xunit`,在某些持续集成环境中很有用。有关更多选项,请参见 `planemo test --help` ,以及 `test_reports` 命令。\r\n\r\n现在,我们可以使用 `serve`(或仅使用 `s` )命令打开 Galaxy。\r\n```bash\r\n$ planemo s\r\n...\r\nserving on http://127.0.0.1:9090\r\n```\r\n\r\n在网络浏览器中打开 [http://127.0.0.1:9090](http://127.0.0.1:9090) 以查看您的新工具。\r\n\r\n服务和测试可以通过各种命令行参数传递,例如 `--galaxy_root`,以指定要使用的 Galaxy 实例(默认情况下,planemo 将仅为 planemo 下载和管理实例)。\r\n\r\n## 简单参数\r\n\r\n我们为 `seqtk seq` 命令构建了一个工具包的封装,但是该工具实际上具有我们可能希望向 Galaxy 用户公开的其他选项。\r\n\r\n让我们从 `help` 命令中获取一些参数,并构建 Galaxy 的 `param` 块以粘贴到该工具的 `input` 块中。\r\n```bash\r\n-V shift quality by \'(-Q) - 33\'\r\n```\r\n\r\n在上一节中,我们看到了输入文件在 `param` 块中是一个 `data` 的类型,除此之外我们还可以使用许多不同种类的参数。如标志参数(例如以上 `-V` 参数),通常在 Galaxy 工具的 XML 文件中由 `boolean` 来表示。\r\n```xml\r\n\r\n```\r\n然后,我们可以将 `$shift_quality` 粘贴在 `command` 块中,如果用户选择了此选项,它将扩展为 `-V` (因为我们已将其定义为 `truevalue` )。如果用户未选择此选项,则 `$shift_quality` 将仅扩展为空字符串,而不会影响生成的命令行。\r\n\r\n现在考虑以下的 `seqtk seq` 参数:\r\n```bash\r\n-q INT mask bases with quality lower than INT [0]\r\n-X INT mask bases with quality higher than INT [255]\r\n```\r\n\r\n这些可以转换为 Galaxy 参数,如下所示:\r\n```xml\r\n\r\n\r\n```\r\n\r\n这些可以作为 `-q $quality_min -X $quality_max` 添加到命令标签中。\r\n\r\n此时,该工具将如下所示:\r\n```xml\r\n\r\n \r\n seqtk\r\n \r\n \'$output1\'\r\n ]]>\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n |\r\n\r\nOptions: -q INT mask bases with quality lower than INT [0]\r\n -X INT mask bases with quality higher than INT [255]\r\n -n CHAR masked bases converted to CHAR; 0 for lowercase [0]\r\n -l INT number of residues per line; 0 for 2^32-1 [0]\r\n -Q INT quality shift: ASCII-INT gives base quality [33]\r\n -s INT random seed (effective with -f) [11]\r\n -f FLOAT sample FLOAT fraction of sequences [1]\r\n -M FILE mask regions in BED or name list FILE [null]\r\n -L INT drop sequences with length shorter than INT [0]\r\n -c mask complement region (effective with -M)\r\n -r reverse complement\r\n -A force FASTA output (discard quality)\r\n -C drop comments at the header lines\r\n -N drop sequences containing ambiguous bases\r\n -1 output the 2n-1 reads only\r\n -2 output the 2n reads only\r\n -V shift quality by \'(-Q) - 33\'\r\n -U convert all bases to uppercases\r\n\r\n\r\n ]]>\r\n \r\n \r\n@misc{githubseqtk,\r\n author = {LastTODO, FirstTODO},\r\n year = {TODO},\r\n title = {seqtk},\r\n publisher = {GitHub},\r\n journal = {GitHub repository},\r\n url = {https://github.com/lh3/seqtk},\r\n}\r\n \r\n\r\n```\r\n\r\n## 条件参数\r\n\r\n以前的参数很简单,因为它们总是出现,现在考虑一下下面的参数。\r\n```bash\r\n-M FILE mask regions in BED or name list FILE [null]\r\n```\r\n\r\n我们可以通过添加属性 `optional ="true"` 将该数据类型参数标记为可选。\r\n```xml\r\n\r\n```\r\n\r\n然后,不仅可以直接在命令块中使用 `$mask_regions`,还可以将其包装在 `if` 语句中(因为工具 XML 文件支持 [Cheetah](https://cheetahtemplate.org/users_guide/index.html))。\r\n```xml\r\n#if $mask_regions\r\n-M \'$mask_regions\'\r\n#end if\r\n```\r\n\r\n\r\n接着,我们考虑这一组参数:\r\n```bash\r\n-s INT random seed (effective with -f) [11]\r\n-f FLOAT sample FLOAT fraction of sequences [1]\r\n```\r\n\r\n在这种情况下,只有在设置了样本参数的情况下,才能看到或使用 `-s` 随机种子参数。我们可以使用 `conditional` 条件块来表达这一点。\r\n```xml\r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n\r\n```\r\n\r\n在命令块中,我们可以再次使用 `if` 语句包括这些参数。\r\n```xml\r\n#if $sample.sample_selector\r\n-f $sample.fraction -s $sample.seed\r\n#end if\r\n```\r\n\r\n注意,我们必须使用 `sample.` 的前缀来引用这个参数,因为它们是在 `sample` 的条件块内定义的。\r\n\r\n现在该工具的最新版本如下:\r\n```xml\r\n\r\n \r\n seqtk\r\n \r\n \'$output1\'\r\n ]]>\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n |\r\n\r\nOptions: -q INT mask bases with quality lower than INT [0]\r\n -X INT mask bases with quality higher than INT [255]\r\n -n CHAR masked bases converted to CHAR; 0 for lowercase [0]\r\n -l INT number of residues per line; 0 for 2^32-1 [0]\r\n -Q INT quality shift: ASCII-INT gives base quality [33]\r\n -s INT random seed (effective with -f) [11]\r\n -f FLOAT sample FLOAT fraction of sequences [1]\r\n -M FILE mask regions in BED or name list FILE [null]\r\n -L INT drop sequences with length shorter than INT [0]\r\n -c mask complement region (effective with -M)\r\n -r reverse complement\r\n -A force FASTA output (discard quality)\r\n -C drop comments at the header lines\r\n -N drop sequences containing ambiguous bases\r\n -1 output the 2n-1 reads only\r\n -2 output the 2n reads only\r\n -V shift quality by \'(-Q) - 33\'\r\n -U convert all bases to uppercases\r\n\r\n\r\n ]]>\r\n \r\n \r\n@misc{githubseqtk,\r\n author = {LastTODO, FirstTODO},\r\n year = {TODO},\r\n title = {seqtk},\r\n publisher = {GitHub},\r\n journal = {GitHub repository},\r\n url = {https://github.com/lh3/seqtk},\r\n}\r\n \r\n\r\n```\r\n对于这样的工具,这些工具有很多选项,但在大多数情况下使用默认值是首选——一个常见的习惯用法是使用条件将参数分为简单部分和高级部分。\r\n\r\n使用惯用法,更新此工具后的 XML 如下所示:\r\n```xml\r\n\r\n \r\n seqtk\r\n \r\n \'$output1\'\r\n ]]>\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n |\r\n\r\nOptions: -q INT mask bases with quality lower than INT [0]\r\n -X INT mask bases with quality higher than INT [255]\r\n -n CHAR masked bases converted to CHAR; 0 for lowercase [0]\r\n -l INT number of residues per line; 0 for 2^32-1 [0]\r\n -Q INT quality shift: ASCII-INT gives base quality [33]\r\n -s INT random seed (effective with -f) [11]\r\n -f FLOAT sample FLOAT fraction of sequences [1]\r\n -M FILE mask regions in BED or name list FILE [null]\r\n -L INT drop sequences with length shorter than INT [0]\r\n -c mask complement region (effective with -M)\r\n -r reverse complement\r\n -A force FASTA output (discard quality)\r\n -C drop comments at the header lines\r\n -N drop sequences containing ambiguous bases\r\n -1 output the 2n-1 reads only\r\n -2 output the 2n reads only\r\n -V shift quality by \'(-Q) - 33\'\r\n -U convert all bases to uppercases\r\n\r\n\r\n ]]>\r\n \r\n \r\n@misc{githubseqtk,\r\n author = {LastTODO, FirstTODO},\r\n year = {TODO},\r\n title = {seqtk},\r\n publisher = {GitHub},\r\n journal = {GitHub repository},\r\n url = {https://github.com/lh3/seqtk},\r\n}\r\n \r\n\r\n```\r\n\r\n## 脚本封装\r\n\r\nTool Shed 上已经提供了许多常见的生物信息学应用程序,因此一项常见的开发任务是将各种复杂程度的脚本集成到 Galaxy 中。\r\n\r\n考虑以下小型 Perl 脚本。\r\n```perl\r\n#!/usr/bin/perl -w\r\n\r\n# usage : perl toolExample.pl \r\n\r\nopen (IN, "<$ARGV[0]");\r\nopen (OUT, ">$ARGV[1]");\r\nwhile () {\r\n chop;\r\n if (m/^>/) {\r\n s/^>//;\r\n if ($. > 1) {\r\n print OUT sprintf("%.3f", $gc/$length) . "\\n";\r\n }\r\n $gc = 0;\r\n $length = 0;\r\n } else {\r\n ++$gc while m/[gc]/ig;\r\n $length += length $_;\r\n }\r\n}\r\nprint OUT sprintf("%.3f", $gc/$length) . "\\n";\r\nclose( IN );\r\nclose( OUT );\r\n```\r\n\r\n可以按照以下步骤为此脚本构建 Galaxy 工具,并将脚本与工具 XML 文件本身放在同一目录中。这里的特殊值 `$__ tool_directory__` 是指工具(即 xml 文件)所在的目录。\r\n```xml\r\n\r\n for each sequence in a file\r\n perl \'$__tool_directory__/gc_content.pl\' \'$input\' output.tsv\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\nThis tool computes GC content from a FASTA file.\r\n \r\n\r\n```\r\n\r\n## Macros 宏集\r\n\r\n如果您希望为单个相对简单的应用程序或脚本编写工具,则应跳过本节。如果您希望维护一系列相关工具——经验表明,您将意识到有很多重复的 XML 可以很好地做到这一点。Galaxy工具 XML 宏可以帮助减少这种重复。\r\n\r\n通过使用 `--macros` 标志,Planemo 的 `tool_init` 命令可用于生成适合工具套件的宏文件。我们看一下以前的 `tool_init` 命令的变体(唯一的区别是现在我们添加了 `--macros` 标志)。\r\n```bash\r\n$ planemo tool_init --force \\\r\n --macros \\\r\n --id \'seqtk_seq\' \\\r\n --name \'Convert to FASTA (seqtk)\' \\\r\n --requirement seqtk@1.2 \\\r\n --example_command \'seqtk seq -A 2.fastq > 2.fasta\' \\\r\n --example_input 2.fastq \\\r\n --example_output 2.fasta \\\r\n --test_case \\\r\n --help_from_command \'seqtk seq\'\r\n```\r\n这将在当前目录中产生两个文件( `seqtk_seq.xml` 和 `macros.xml`),而不是一个。\r\n```xml\r\n\r\n \r\n macros.xml\r\n \r\n \r\n \'$output1\'\r\n ]]>\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n |\r\n\r\nOptions: -q INT mask bases with quality lower than INT [0]\r\n -X INT mask bases with quality higher than INT [255]\r\n -n CHAR masked bases converted to CHAR; 0 for lowercase [0]\r\n -l INT number of residues per line; 0 for 2^32-1 [0]\r\n -Q INT quality shift: ASCII-INT gives base quality [33]\r\n -s INT random seed (effective with -f) [11]\r\n -f FLOAT sample FLOAT fraction of sequences [1]\r\n -M FILE mask regions in BED or name list FILE [null]\r\n -L INT drop sequences with length shorter than INT [0]\r\n -c mask complement region (effective with -M)\r\n -r reverse complement\r\n -A force FASTA output (discard quality)\r\n -C drop comments at the header lines\r\n -N drop sequences containing ambiguous bases\r\n -1 output the 2n-1 reads only\r\n -2 output the 2n reads only\r\n -V shift quality by \'(-Q) - 33\'\r\n -U convert all bases to uppercases\r\n -S strip of white spaces in sequences\r\n\r\n\r\n ]]>\r\n \r\n\r\n```\r\n```xml\r\n\r\n \r\n \r\n seqtk\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n\r\n```\r\n\r\n如您在上面的代码中所看到的,宏是可重用的 XML 块,它们使避免重复和保持 XML 简洁变得更加容易。\r\n\r\n\r\n## 参考资料\r\n\r\n- [Macros syntax](https://wiki.galaxyproject.org/Admin/Tools/ToolConfigSyntax#Reusing_Repeated_Configuration_Elements) on the Galaxy Wiki.\r\n- [GATK tools](https://github.com/galaxyproject/tools-iuc/tree/master/tools/gatk2) (example tools making extensive use of macros)\r\n- [gemini tools](https://github.com/galaxyproject/tools-iuc/tree/master/tools/gemini) (example tools making extensive use of macros)\r\n- [bedtools tools](https://github.com/galaxyproject/tools-iuc/tree/master/tools/bedtools) (example tools making extensive use of macros)\r\n- Macros implementation details - [Pull Request #129](https://bitbucket.org/galaxy/galaxy-central/pull-request/129/implement-macro-engine-to-reduce-tool/diff) and [Pull Request #140](https://bitbucket.org/galaxy/galaxy-central/pull-request/140/improvements-to-tool-xml-macroing-system/diff)\r\n- [Galaxy’s Tool XML Syntax](https://docs.galaxyproject.org/en/latest/dev/schema.html)\r\n- [Big List of Tool Development Resources](https://galaxyproject.org/develop/resources-tools/)\r\n- [Cheetah templating](https://cheetahtemplate.org/users_guide/index.html)', 'bodyText': '说明:本文章原文发布于 《使用 Planemo 进行 Galaxy 工具开发 - 语雀》,部分内容已更新。\n\n文章开始前,我们先了解一下 Planemo 到底是个什么东西。\n\nCommand-line utilities to assist in developing Galaxy and Common Workflow Language artifacts - including tools, workflows, and training materials.\n\n说白了,Planemo 就是用于 Galaxy 平台工具和 WDL 通用工作流语言相关产品辅助开发的一个命令行工具,这个程序集可以用于工具、流程,以及培训教材的开发。\n\n安装 Planemo\n无论是 pip 还是 conda 都可以安装 Planemo:\n$ pip install planemo\n$ pip install -U git+git://github.com/galaxyproject/planemo.git\n$ conda config --add channels bioconda\n$ conda config --add channels conda-forge\n$ conda install planemo\n接下来,进入今天的正题,我们来详细介绍一下怎么使用 Planemo 进行 Galaxy 工具开发。\n基础用法\n本指南将演示如何使用 Heng Li 的 Seqtk 软件包构建命令工具,该软件包用于处理 FASTA 和 FASTQ 文件中的序列数据。\n首先,我们需要先安装 Seqtk 。在这里,我们使用 conda 来安装 Seqtk (你也可以使用其他的方法安装)。\n$ conda install --force --yes -c conda-forge -c bioconda seqtk=1.2\n ... seqtk installation ...\n$ seqtk seq\n Usage: seqtk seq [options] |\n Options: -q INT mask bases with quality lower than INT [0]\n -X INT mask bases with quality higher than INT [255]\n -n CHAR masked bases converted to CHAR; 0 for lowercase [0]\n -l INT number of residues per line; 0 for 2^32-1 [0]\n -Q INT quality shift: ASCII-INT gives base quality [33]\n -s INT random seed (effective with -f) [11]\n -f FLOAT sample FLOAT fraction of sequences [1]\n -M FILE mask regions in BED or name list FILE [null]\n -L INT drop sequences with length shorter than INT [0]\n -c mask complement region (effective with -M)\n -r reverse complement\n -A force FASTA output (discard quality)\n -C drop comments at the header lines\n -N drop sequences containing ambiguous bases\n -1 output the 2n-1 reads only\n -2 output the 2n reads only\n -V shift quality by \'(-Q) - 33\'\n接下来,我们将下载一个 FASTQ 示例文件,并测试一个简单的 Seqtk 命令 seq ,该命令将 FASTQ 文件转换为 FASTA。\n$ wget https://raw.githubusercontent.com/galaxyproject/galaxy-test-data/master/2.fastq\n$ seqtk seq -A 2.fastq > 2.fasta\n$ cat 2.fasta\n>EAS54_6_R1_2_1_413_324\nCCCTTCTTGTCTTCAGCGTTTCTCC\n>EAS54_6_R1_2_1_540_792\nTTGGCAGGCCAAGGCCGATGGATCA\n>EAS54_6_R1_2_1_443_348\nGTTGCTTCTGGCGTGGGTGGGGGGG\n有关功能齐全的 Seqtk 包封装,可以在 GitHub 上查看 Helena Rasche\'s wrappers。\nGalaxy 工具文件只是 XML 文件,因此此时可以打开文本编辑器并开始编写工具。Planemo 有一个命令 tool_init 可以快速生成一些样板 XML,因此首先开始。\n$ planemo tool_init --id \'seqtk_seq\' --name \'Convert to FASTA (seqtk)\'\ntool_init 命令可以采用各种复杂的参数,但如上面展示的 --id 和 --name 是其中两个最基本的参数。每个 Galaxy 工具都需要一个 ID(这是 Galaxy 自身用来标识该工具的简短标识符)和一个名称(此名称会显示给 Galaxy 用户,并且应该是该工具的简短描述)。工具名称可以包含空格,但其 ID 不能包含空格。\n上面的命令将生成一个 seqtk_seq.xml 文件,这个文件看起来像这样:\n\n \n \n \n \n \n \n \n \n\n这个生成的模板 XML 文件具有了 Galaxy 工具所需的公共部分内容,但你仍然需要打开编辑器并填写命令模板、输入参数描述、工具输出信息、帮助部分信息等。\ntool_init 命令也可以做得更好。 们可以使用在 seqtk seq -a 2.fastq> 2.fasta 上面尝试过的测试命令作为示例,通过指定输入和输出来生成命令块,如下所示。\n$ planemo tool_init --force \\\n --id \'seqtk_seq\' \\\n --name \'Convert to FASTA (seqtk)\' \\\n --requirement seqtk@1.2 \\\n --example_command \'seqtk seq -a 2.fastq > 2.fasta\' \\\n --example_input 2.fastq \\\n --example_output 2.fasta\n这将生成以下 XML 文件- 该文件具有正确的输入和输出定义以及实际的命令模板。\n\n \n seqtk\n \n \'$output1\'\n ]]>\n \n \n \n \n \n \n \n(\n如本节开头所示,命令 seqtk seq 会为 seq 命令生成帮助消息。 tool_init 可以获取该帮助消息,并使用 help_from_command 选项将其正确粘贴在生成的工具 XML 文件中。\n通常,命令帮助消息并不完全适用于工具,因为它们会提到参数名称和由工具抽象出来的类似细节,但它们可能是一个很好的起点。\n以下 Planemo 的 tool_init 的调用已增强为使用 --help_from_command。\n$ planemo tool_init --force \\\n --id \'seqtk_seq\' \\\n --name \'Convert to FASTA (seqtk)\' \\\n --requirement seqtk@1.2 \\\n --example_command \'seqtk seq -a 2.fastq > 2.fasta\' \\\n --example_input 2.fastq \\\n --example_output 2.fasta \\\n --test_case \\\n --cite_url \'https://github.com/lh3/seqtk\' \\\n --help_from_command \'seqtk seq\'\n除了演示 --help_from_command 之外,这还演示了使用 --test_case 从我们的示例生成测试用例并为基础工具添加引用。生成的工具 XML 文件为:\n\n \n seqtk\n \n \'$output1\'\n ]]>\n \n \n \n \n \n \n \n \n \n \n \n \n |\n\nOptions: -q INT mask bases with quality lower than INT [0]\n -X INT mask bases with quality higher than INT [255]\n -n CHAR masked bases converted to CHAR; 0 for lowercase [0]\n -l INT number of residues per line; 0 for 2^32-1 [0]\n -Q INT quality shift: ASCII-INT gives base quality [33]\n -s INT random seed (effective with -f) [11]\n -f FLOAT sample FLOAT fraction of sequences [1]\n -M FILE mask regions in BED or name list FILE [null]\n -L INT drop sequences with length shorter than INT [0]\n -c mask complement region (effective with -M)\n -r reverse complement\n -A force FASTA output (discard quality)\n -C drop comments at the header lines\n -N drop sequences containing ambiguous bases\n -1 output the 2n-1 reads only\n -2 output the 2n reads only\n -V shift quality by \'(-Q) - 33\'\n -U convert all bases to uppercases\n -S strip of white spaces in sequences\n\n\n ]]>\n \n \n@misc{githubseqtk,\n author = {LastTODO, FirstTODO},\n year = {TODO},\n title = {seqtk},\n publisher = {GitHub},\n journal = {GitHub repository},\n url = {https://github.com/lh3/seqtk},\n}\n \n\n至此,我们有了一个功能相当齐全的 Galaxy 工具,它带有测试和帮助。这是一个非常简单的示例——通常,您需要在工具中投入更多工作才能实现这一点, tool_init 实际上只是为了让您入门而设计的。\n现在让我们检查并测试我们开发的工具。Planemo的 lint(或仅 l )命令将检查工具的 XML 有效性,检查是否有明显的错误以及是否符合 IUC 的最佳做法。\n$ planemo l\nLinting tool /opt/galaxy/tools/seqtk_seq.xml\nApplying linter tests... CHECK\n.. CHECK: 1 test(s) found.\nApplying linter output... CHECK\n.. INFO: 1 outputs found.\nApplying linter inputs... CHECK\n.. INFO: Found 1 input parameters.\nApplying linter help... CHECK\n.. CHECK: Tool contains help section.\n.. CHECK: Help contains valid reStructuredText.\nApplying linter general... CHECK\n.. CHECK: Tool defines a version [0.1.0].\n.. CHECK: Tool defines a name [Convert to FASTA (seqtk)].\n.. CHECK: Tool defines an id [seqtk_seq].\n.. CHECK: Tool targets 16.01 Galaxy profile.\nApplying linter command... CHECK\n.. INFO: Tool contains a command.\nApplying linter citations... CHECK\n.. CHECK: Found 1 likely valid citations.\nApplying linter tool_xsd... CHECK\n.. INFO: File validates against XML schema.\n默认情况下, lint 会在您当前的工作目录中找到所有工具,但是我们可以使用 planemo lint seqtk_seq.xml 指定一个特定的工具。\n接下来,我们可以使用 test(或仅执行 t )命令运行工具的功能测试。这将打印很多输出(因为它启动了 Galaxy 实例),但最终应该显示我们通过的一项测试。\n\n如果你的服务器已经安装了 Galaxy 实例,你可以编辑 ~/.planemo.yml 文件,指定 Galaxy 实例路径。\n\n## Specify a default galaxy_root for the `test` and `serve` commands here.\ngalaxy_root: /home/user/galaxy\n\n完整的 ~/.planemo.yml 示例,参考:https://planemo.readthedocs.io/en/latest/configuration.html\n\n$ planemo t\n...\nAll 1 test(s) executed passed.\nseqtk_seq[0]: passed\n除了在控制台中将测试结果显示为红色(失败)或绿色(通过)外,Planemo 还默认为测试结果创建 HTML 报告。 还有更多测试报告选项可用,例如 --test_output_xunit,在某些持续集成环境中很有用。有关更多选项,请参见 planemo test --help ,以及 test_reports 命令。\n现在,我们可以使用 serve(或仅使用 s )命令打开 Galaxy。\n$ planemo s\n...\nserving on http://127.0.0.1:9090\n在网络浏览器中打开 http://127.0.0.1:9090 以查看您的新工具。\n服务和测试可以通过各种命令行参数传递,例如 --galaxy_root,以指定要使用的 Galaxy 实例(默认情况下,planemo 将仅为 planemo 下载和管理实例)。\n简单参数\n我们为 seqtk seq 命令构建了一个工具包的封装,但是该工具实际上具有我们可能希望向 Galaxy 用户公开的其他选项。\n让我们从 help 命令中获取一些参数,并构建 Galaxy 的 param 块以粘贴到该工具的 input 块中。\n-V shift quality by \'(-Q) - 33\'\n在上一节中,我们看到了输入文件在 param 块中是一个 data 的类型,除此之外我们还可以使用许多不同种类的参数。如标志参数(例如以上 -V 参数),通常在 Galaxy 工具的 XML 文件中由 boolean 来表示。\n\n然后,我们可以将 $shift_quality 粘贴在 command 块中,如果用户选择了此选项,它将扩展为 -V (因为我们已将其定义为 truevalue )。如果用户未选择此选项,则 $shift_quality 将仅扩展为空字符串,而不会影响生成的命令行。\n现在考虑以下的 seqtk seq 参数:\n-q INT mask bases with quality lower than INT [0]\n-X INT mask bases with quality higher than INT [255]\n这些可以转换为 Galaxy 参数,如下所示:\n\n\n这些可以作为 -q $quality_min -X $quality_max 添加到命令标签中。\n此时,该工具将如下所示:\n\n \n seqtk\n \n \'$output1\'\n ]]>\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n |\n\nOptions: -q INT mask bases with quality lower than INT [0]\n -X INT mask bases with quality higher than INT [255]\n -n CHAR masked bases converted to CHAR; 0 for lowercase [0]\n -l INT number of residues per line; 0 for 2^32-1 [0]\n -Q INT quality shift: ASCII-INT gives base quality [33]\n -s INT random seed (effective with -f) [11]\n -f FLOAT sample FLOAT fraction of sequences [1]\n -M FILE mask regions in BED or name list FILE [null]\n -L INT drop sequences with length shorter than INT [0]\n -c mask complement region (effective with -M)\n -r reverse complement\n -A force FASTA output (discard quality)\n -C drop comments at the header lines\n -N drop sequences containing ambiguous bases\n -1 output the 2n-1 reads only\n -2 output the 2n reads only\n -V shift quality by \'(-Q) - 33\'\n -U convert all bases to uppercases\n\n\n ]]>\n \n \n@misc{githubseqtk,\n author = {LastTODO, FirstTODO},\n year = {TODO},\n title = {seqtk},\n publisher = {GitHub},\n journal = {GitHub repository},\n url = {https://github.com/lh3/seqtk},\n}\n \n\n条件参数\n以前的参数很简单,因为它们总是出现,现在考虑一下下面的参数。\n-M FILE mask regions in BED or name list FILE [null]\n我们可以通过添加属性 optional ="true" 将该数据类型参数标记为可选。\n\n然后,不仅可以直接在命令块中使用 $mask_regions,还可以将其包装在 if 语句中(因为工具 XML 文件支持 Cheetah)。\n#if $mask_regions\n-M \'$mask_regions\'\n#end if\n接着,我们考虑这一组参数:\n-s INT random seed (effective with -f) [11]\n-f FLOAT sample FLOAT fraction of sequences [1]\n在这种情况下,只有在设置了样本参数的情况下,才能看到或使用 -s 随机种子参数。我们可以使用 conditional 条件块来表达这一点。\n\n \n \n \n \n \n \n \n\n在命令块中,我们可以再次使用 if 语句包括这些参数。\n#if $sample.sample_selector\n-f $sample.fraction -s $sample.seed\n#end if\n注意,我们必须使用 sample. 的前缀来引用这个参数,因为它们是在 sample 的条件块内定义的。\n现在该工具的最新版本如下:\n\n \n seqtk\n \n \'$output1\'\n ]]>\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n |\n\nOptions: -q INT mask bases with quality lower than INT [0]\n -X INT mask bases with quality higher than INT [255]\n -n CHAR masked bases converted to CHAR; 0 for lowercase [0]\n -l INT number of residues per line; 0 for 2^32-1 [0]\n -Q INT quality shift: ASCII-INT gives base quality [33]\n -s INT random seed (effective with -f) [11]\n -f FLOAT sample FLOAT fraction of sequences [1]\n -M FILE mask regions in BED or name list FILE [null]\n -L INT drop sequences with length shorter than INT [0]\n -c mask complement region (effective with -M)\n -r reverse complement\n -A force FASTA output (discard quality)\n -C drop comments at the header lines\n -N drop sequences containing ambiguous bases\n -1 output the 2n-1 reads only\n -2 output the 2n reads only\n -V shift quality by \'(-Q) - 33\'\n -U convert all bases to uppercases\n\n\n ]]>\n \n \n@misc{githubseqtk,\n author = {LastTODO, FirstTODO},\n year = {TODO},\n title = {seqtk},\n publisher = {GitHub},\n journal = {GitHub repository},\n url = {https://github.com/lh3/seqtk},\n}\n \n\n对于这样的工具,这些工具有很多选项,但在大多数情况下使用默认值是首选——一个常见的习惯用法是使用条件将参数分为简单部分和高级部分。\n使用惯用法,更新此工具后的 XML 如下所示:\n\n \n seqtk\n \n \'$output1\'\n ]]>\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n |\n\nOptions: -q INT mask bases with quality lower than INT [0]\n -X INT mask bases with quality higher than INT [255]\n -n CHAR masked bases converted to CHAR; 0 for lowercase [0]\n -l INT number of residues per line; 0 for 2^32-1 [0]\n -Q INT quality shift: ASCII-INT gives base quality [33]\n -s INT random seed (effective with -f) [11]\n -f FLOAT sample FLOAT fraction of sequences [1]\n -M FILE mask regions in BED or name list FILE [null]\n -L INT drop sequences with length shorter than INT [0]\n -c mask complement region (effective with -M)\n -r reverse complement\n -A force FASTA output (discard quality)\n -C drop comments at the header lines\n -N drop sequences containing ambiguous bases\n -1 output the 2n-1 reads only\n -2 output the 2n reads only\n -V shift quality by \'(-Q) - 33\'\n -U convert all bases to uppercases\n\n\n ]]>\n \n \n@misc{githubseqtk,\n author = {LastTODO, FirstTODO},\n year = {TODO},\n title = {seqtk},\n publisher = {GitHub},\n journal = {GitHub repository},\n url = {https://github.com/lh3/seqtk},\n}\n \n\n脚本封装\nTool Shed 上已经提供了许多常见的生物信息学应用程序,因此一项常见的开发任务是将各种复杂程度的脚本集成到 Galaxy 中。\n考虑以下小型 Perl 脚本。\n#!/usr/bin/perl -w\n\n# usage : perl toolExample.pl \n\nopen (IN, "<$ARGV[0]");\nopen (OUT, ">$ARGV[1]");\nwhile () {\n chop;\n if (m/^>/) {\n s/^>//;\n if ($. > 1) {\n print OUT sprintf("%.3f", $gc/$length) . "\\n";\n }\n $gc = 0;\n $length = 0;\n } else {\n ++$gc while m/[gc]/ig;\n $length += length $_;\n }\n}\nprint OUT sprintf("%.3f", $gc/$length) . "\\n";\nclose( IN );\nclose( OUT );\n可以按照以下步骤为此脚本构建 Galaxy 工具,并将脚本与工具 XML 文件本身放在同一目录中。这里的特殊值 $__ tool_directory__ 是指工具(即 xml 文件)所在的目录。\n\n for each sequence in a file\n perl \'$__tool_directory__/gc_content.pl\' \'$input\' output.tsv\n \n \n \n \n \n \n \nThis tool computes GC content from a FASTA file.\n \n\nMacros 宏集\n如果您希望为单个相对简单的应用程序或脚本编写工具,则应跳过本节。如果您希望维护一系列相关工具——经验表明,您将意识到有很多重复的 XML 可以很好地做到这一点。Galaxy工具 XML 宏可以帮助减少这种重复。\n通过使用 --macros 标志,Planemo 的 tool_init 命令可用于生成适合工具套件的宏文件。我们看一下以前的 tool_init 命令的变体(唯一的区别是现在我们添加了 --macros 标志)。\n$ planemo tool_init --force \\\n --macros \\\n --id \'seqtk_seq\' \\\n --name \'Convert to FASTA (seqtk)\' \\\n --requirement seqtk@1.2 \\\n --example_command \'seqtk seq -A 2.fastq > 2.fasta\' \\\n --example_input 2.fastq \\\n --example_output 2.fasta \\\n --test_case \\\n --help_from_command \'seqtk seq\'\n这将在当前目录中产生两个文件( seqtk_seq.xml 和 macros.xml),而不是一个。\n\n \n macros.xml\n \n \n \'$output1\'\n ]]>\n \n \n \n \n \n \n \n \n \n \n \n \n |\n\nOptions: -q INT mask bases with quality lower than INT [0]\n -X INT mask bases with quality higher than INT [255]\n -n CHAR masked bases converted to CHAR; 0 for lowercase [0]\n -l INT number of residues per line; 0 for 2^32-1 [0]\n -Q INT quality shift: ASCII-INT gives base quality [33]\n -s INT random seed (effective with -f) [11]\n -f FLOAT sample FLOAT fraction of sequences [1]\n -M FILE mask regions in BED or name list FILE [null]\n -L INT drop sequences with length shorter than INT [0]\n -c mask complement region (effective with -M)\n -r reverse complement\n -A force FASTA output (discard quality)\n -C drop comments at the header lines\n -N drop sequences containing ambiguous bases\n -1 output the 2n-1 reads only\n -2 output the 2n reads only\n -V shift quality by \'(-Q) - 33\'\n -U convert all bases to uppercases\n -S strip of white spaces in sequences\n\n\n ]]>\n \n\n\n \n \n seqtk\n \n \n \n \n \n \n \n \n\n如您在上面的代码中所看到的,宏是可重用的 XML 块,它们使避免重复和保持 XML 简洁变得更加容易。\n参考资料\n\nMacros syntax on the Galaxy Wiki.\nGATK tools (example tools making extensive use of macros)\ngemini tools (example tools making extensive use of macros)\nbedtools tools (example tools making extensive use of macros)\nMacros implementation details - Pull Request #129 and Pull Request #140\nGalaxy’s Tool XML Syntax\nBig List of Tool Development Resources\nCheetah templating', 'bodyHTML': '
\n

说明:本文章原文发布于 《使用 Planemo 进行 Galaxy 工具开发 - 语雀》,部分内容已更新。

\n
\n

文章开始前,我们先了解一下 Planemo 到底是个什么东西。

\n
\n

Command-line utilities to assist in developing Galaxy and Common Workflow Language artifacts - including tools, workflows, and training materials.

\n
\n

说白了,Planemo 就是用于 Galaxy 平台工具和 WDL 通用工作流语言相关产品辅助开发的一个命令行工具,这个程序集可以用于工具、流程,以及培训教材的开发。

\n\n

安装 Planemo

\n

无论是 pip 还是 conda 都可以安装 Planemo:

\n
$ pip install planemo\n$ pip install -U git+git://github.com/galaxyproject/planemo.git
\n
$ conda config --add channels bioconda\n$ conda config --add channels conda-forge\n$ conda install planemo
\n

接下来,进入今天的正题,我们来详细介绍一下怎么使用 Planemo 进行 Galaxy 工具开发。

\n

基础用法

\n

本指南将演示如何使用 Heng Li 的 Seqtk 软件包构建命令工具,该软件包用于处理 FASTA 和 FASTQ 文件中的序列数据。

\n

首先,我们需要先安装 Seqtk 。在这里,我们使用 conda 来安装 Seqtk (你也可以使用其他的方法安装)。

\n
$ conda install --force --yes -c conda-forge -c bioconda seqtk=1.2\n    ... seqtk installation ...\n$ seqtk seq\n        Usage:   seqtk seq [options] <in.fq>|<in.fa>\n        Options: -q INT    mask bases with quality lower than INT [0]\n                 -X INT    mask bases with quality higher than INT [255]\n                 -n CHAR   masked bases converted to CHAR; 0 for lowercase [0]\n                 -l INT    number of residues per line; 0 for 2^32-1 [0]\n                 -Q INT    quality shift: ASCII-INT gives base quality [33]\n                 -s INT    random seed (effective with -f) [11]\n                 -f FLOAT  sample FLOAT fraction of sequences [1]\n                 -M FILE   mask regions in BED or name list FILE [null]\n                 -L INT    drop sequences with length shorter than INT [0]\n                 -c        mask complement region (effective with -M)\n                 -r        reverse complement\n                 -A        force FASTA output (discard quality)\n                 -C        drop comments at the header lines\n                 -N        drop sequences containing ambiguous bases\n                 -1        output the 2n-1 reads only\n                 -2        output the 2n reads only\n                 -V        shift quality by \'(-Q) - 33\'
\n

接下来,我们将下载一个 FASTQ 示例文件,并测试一个简单的 Seqtk 命令 seq ,该命令将 FASTQ 文件转换为 FASTA。

\n
$ wget https://raw.githubusercontent.com/galaxyproject/galaxy-test-data/master/2.fastq\n$ seqtk seq -A 2.fastq > 2.fasta\n$ cat 2.fasta\n>EAS54_6_R1_2_1_413_324\nCCCTTCTTGTCTTCAGCGTTTCTCC\n>EAS54_6_R1_2_1_540_792\nTTGGCAGGCCAAGGCCGATGGATCA\n>EAS54_6_R1_2_1_443_348\nGTTGCTTCTGGCGTGGGTGGGGGGG
\n

有关功能齐全的 Seqtk 包封装,可以在 GitHub 上查看 Helena Rasche\'s wrappers

\n

Galaxy 工具文件只是 XML 文件,因此此时可以打开文本编辑器并开始编写工具。Planemo 有一个命令 tool_init 可以快速生成一些样板 XML,因此首先开始。

\n
$ planemo tool_init --id \'seqtk_seq\' --name \'Convert to FASTA (seqtk)\'
\n

tool_init 命令可以采用各种复杂的参数,但如上面展示的 --id--name 是其中两个最基本的参数。每个 Galaxy 工具都需要一个 ID(这是 Galaxy 自身用来标识该工具的简短标识符)和一个名称(此名称会显示给 Galaxy 用户,并且应该是该工具的简短描述)。工具名称可以包含空格,但其 ID 不能包含空格。

\n

上面的命令将生成一个 seqtk_seq.xml 文件,这个文件看起来像这样:

\n
<tool id="seqtk_seq" name="Convert to FASTA (seqtk)" version="0.1.0" python_template_version="3.5">\n    <requirements>\n    </requirements>\n    <command detect_errors="exit_code"><![CDATA[\n        TODO: Fill in command template.\n    ]]></command>\n    <inputs>\n    </inputs>\n    <outputs>\n    </outputs>\n    <help><![CDATA[\n        TODO: Fill in help.\n    ]]></help>\n</tool>
\n

这个生成的模板 XML 文件具有了 Galaxy 工具所需的公共部分内容,但你仍然需要打开编辑器并填写命令模板、输入参数描述、工具输出信息、帮助部分信息等。

\n

tool_init 命令也可以做得更好。 们可以使用在 seqtk seq -a 2.fastq> 2.fasta 上面尝试过的测试命令作为示例,通过指定输入和输出来生成命令块,如下所示。

\n
$ planemo tool_init --force \\\n                    --id \'seqtk_seq\' \\\n                    --name \'Convert to FASTA (seqtk)\' \\\n                    --requirement seqtk@1.2 \\\n                    --example_command \'seqtk seq -a 2.fastq > 2.fasta\' \\\n                    --example_input 2.fastq \\\n                    --example_output 2.fasta
\n

这将生成以下 XML 文件- 该文件具有正确的输入和输出定义以及实际的命令模板。

\n
<tool id="seqtk_seq" name="Convert to FASTA (seqtk)" version="0.1.0" python_template_version="3.5">\n    <requirements>\n        <requirement type="package" version="1.2">seqtk</requirement>\n    </requirements>\n    <command detect_errors="exit_code"><![CDATA[\n        seqtk seq -a \'$input1\' > \'$output1\'\n    ]]></command>\n    <inputs>\n        <param type="data" name="input1" format="fastq" />\n    </inputs>\n    <outputs>\n        <data name="output1" format="fasta" />\n    </outputs>\n    <help><![CDATA[\n        TODO: Fill in help.\n    ]]></help>\n</tool>(
\n

如本节开头所示,命令 seqtk seq 会为 seq 命令生成帮助消息。 tool_init 可以获取该帮助消息,并使用 help_from_command 选项将其正确粘贴在生成的工具 XML 文件中。

\n

通常,命令帮助消息并不完全适用于工具,因为它们会提到参数名称和由工具抽象出来的类似细节,但它们可能是一个很好的起点。

\n

以下 Planemo 的 tool_init 的调用已增强为使用 --help_from_command

\n
$ planemo tool_init --force \\\n                    --id \'seqtk_seq\' \\\n                    --name \'Convert to FASTA (seqtk)\' \\\n                    --requirement seqtk@1.2 \\\n                    --example_command \'seqtk seq -a 2.fastq > 2.fasta\' \\\n                    --example_input 2.fastq \\\n                    --example_output 2.fasta \\\n                    --test_case \\\n                    --cite_url \'https://github.com/lh3/seqtk\' \\\n                    --help_from_command \'seqtk seq\'
\n

除了演示 --help_from_command 之外,这还演示了使用 --test_case 从我们的示例生成测试用例并为基础工具添加引用。生成的工具 XML 文件为:

\n
<tool id="seqtk_seq" name="Convert to FASTA (seqtk)" version="0.1.0" python_template_version="3.5">\n    <requirements>\n        <requirement type="package" version="1.2">seqtk</requirement>\n    </requirements>\n    <command detect_errors="exit_code"><![CDATA[\n        seqtk seq -a \'$input1\' > \'$output1\'\n    ]]></command>\n    <inputs>\n        <param type="data" name="input1" format="fastq" />\n    </inputs>\n    <outputs>\n        <data name="output1" format="fasta" />\n    </outputs>\n    <tests>\n        <test>\n            <param name="input1" value="2.fastq"/>\n            <output name="output1" file="2.fasta"/>\n        </test>\n    </tests>\n    <help><![CDATA[\n\nUsage:   seqtk seq [options] <in.fq>|<in.fa>\n\nOptions: -q INT    mask bases with quality lower than INT [0]\n         -X INT    mask bases with quality higher than INT [255]\n         -n CHAR   masked bases converted to CHAR; 0 for lowercase [0]\n         -l INT    number of residues per line; 0 for 2^32-1 [0]\n         -Q INT    quality shift: ASCII-INT gives base quality [33]\n         -s INT    random seed (effective with -f) [11]\n         -f FLOAT  sample FLOAT fraction of sequences [1]\n         -M FILE   mask regions in BED or name list FILE [null]\n         -L INT    drop sequences with length shorter than INT [0]\n         -c        mask complement region (effective with -M)\n         -r        reverse complement\n         -A        force FASTA output (discard quality)\n         -C        drop comments at the header lines\n         -N        drop sequences containing ambiguous bases\n         -1        output the 2n-1 reads only\n         -2        output the 2n reads only\n         -V        shift quality by \'(-Q) - 33\'\n         -U        convert all bases to uppercases\n         -S        strip of white spaces in sequences\n\n\n    ]]></help>\n    <citations>\n        <citation type="bibtex">\n@misc{githubseqtk,\n  author = {LastTODO, FirstTODO},\n  year = {TODO},\n  title = {seqtk},\n  publisher = {GitHub},\n  journal = {GitHub repository},\n  url = {https://github.com/lh3/seqtk},\n}</citation>\n    </citations>\n</tool>
\n

至此,我们有了一个功能相当齐全的 Galaxy 工具,它带有测试和帮助。这是一个非常简单的示例——通常,您需要在工具中投入更多工作才能实现这一点, tool_init 实际上只是为了让您入门而设计的。

\n

现在让我们检查并测试我们开发的工具。Planemo的 lint(或仅 l )命令将检查工具的 XML 有效性,检查是否有明显的错误以及是否符合 IUC 的最佳做法。

\n
$ planemo l\nLinting tool /opt/galaxy/tools/seqtk_seq.xml\nApplying linter tests... CHECK\n.. CHECK: 1 test(s) found.\nApplying linter output... CHECK\n.. INFO: 1 outputs found.\nApplying linter inputs... CHECK\n.. INFO: Found 1 input parameters.\nApplying linter help... CHECK\n.. CHECK: Tool contains help section.\n.. CHECK: Help contains valid reStructuredText.\nApplying linter general... CHECK\n.. CHECK: Tool defines a version [0.1.0].\n.. CHECK: Tool defines a name [Convert to FASTA (seqtk)].\n.. CHECK: Tool defines an id [seqtk_seq].\n.. CHECK: Tool targets 16.01 Galaxy profile.\nApplying linter command... CHECK\n.. INFO: Tool contains a command.\nApplying linter citations... CHECK\n.. CHECK: Found 1 likely valid citations.\nApplying linter tool_xsd... CHECK\n.. INFO: File validates against XML schema.
\n

默认情况下, lint 会在您当前的工作目录中找到所有工具,但是我们可以使用 planemo lint seqtk_seq.xml 指定一个特定的工具。

\n

接下来,我们可以使用 test(或仅执行 t )命令运行工具的功能测试。这将打印很多输出(因为它启动了 Galaxy 实例),但最终应该显示我们通过的一项测试。

\n
\n

如果你的服务器已经安装了 Galaxy 实例,你可以编辑 ~/.planemo.yml 文件,指定 Galaxy 实例路径。

\n
\n
## Specify a default galaxy_root for the `test` and `serve` commands here.\ngalaxy_root: /home/user/galaxy
\n
\n

完整的 ~/.planemo.yml 示例,参考:https://planemo.readthedocs.io/en/latest/configuration.html

\n
\n
$ planemo t\n...\nAll 1 test(s) executed passed.\nseqtk_seq[0]: passed
\n

除了在控制台中将测试结果显示为红色(失败)或绿色(通过)外,Planemo 还默认为测试结果创建 HTML 报告。 还有更多测试报告选项可用,例如 --test_output_xunit,在某些持续集成环境中很有用。有关更多选项,请参见 planemo test --help ,以及 test_reports 命令。

\n

现在,我们可以使用 serve(或仅使用 s )命令打开 Galaxy。

\n
$ planemo s\n...\nserving on http://127.0.0.1:9090
\n

在网络浏览器中打开 http://127.0.0.1:9090 以查看您的新工具。

\n

服务和测试可以通过各种命令行参数传递,例如 --galaxy_root,以指定要使用的 Galaxy 实例(默认情况下,planemo 将仅为 planemo 下载和管理实例)。

\n

简单参数

\n

我们为 seqtk seq 命令构建了一个工具包的封装,但是该工具实际上具有我们可能希望向 Galaxy 用户公开的其他选项。

\n

让我们从 help 命令中获取一些参数,并构建 Galaxy 的 param 块以粘贴到该工具的 input 块中。

\n
-V        shift quality by \'(-Q) - 33\'
\n

在上一节中,我们看到了输入文件在 param 块中是一个 data 的类型,除此之外我们还可以使用许多不同种类的参数。如标志参数(例如以上 -V 参数),通常在 Galaxy 工具的 XML 文件中由 boolean 来表示。

\n
<param name="shift_quality" type="boolean" label="Shift quality"\n       truevalue="-V" falsevalue=""\n       help="shift quality by \'(-Q) - 33\' (-V)" />
\n

然后,我们可以将 $shift_quality 粘贴在 command 块中,如果用户选择了此选项,它将扩展为 -V (因为我们已将其定义为 truevalue )。如果用户未选择此选项,则 $shift_quality 将仅扩展为空字符串,而不会影响生成的命令行。

\n

现在考虑以下的 seqtk seq 参数:

\n
-q INT    mask bases with quality lower than INT [0]\n-X INT    mask bases with quality higher than INT [255]
\n

这些可以转换为 Galaxy 参数,如下所示:

\n
<param name="quality_min" type="integer" label="Mask bases with quality lower than"\n       value="0" min="0" max="255" help="(-q)" />\n<param name="quality_max" type="integer" label="Mask bases with quality higher than"\n       value="255" min="0" max="255" help="(-X)" />
\n

这些可以作为 -q $quality_min -X $quality_max 添加到命令标签中。

\n

此时,该工具将如下所示:

\n
<tool id="seqtk_seq" name="Convert to FASTA (seqtk)" version="0.1.0" python_template_version="3.5">\n    <requirements>\n        <requirement type="package" version="1.2">seqtk</requirement>\n    </requirements>\n    <command detect_errors="exit_code"><![CDATA[\n        seqtk seq\n              $shift_quality\n              -q $quality_min\n              -X $quality_max\n              -a \'$input1\' > \'$output1\'\n    ]]></command>\n    <inputs>\n        <param type="data" name="input1" format="fastq" />\n        <param name="shift_quality" type="boolean" label="Shift quality" \n               truevalue="-V" falsevalue=""\n               help="shift quality by \'(-Q) - 33\' (-V)" />\n        <param name="quality_min" type="integer" label="Mask bases with quality lower than" \n               value="0" min="0" max="255" help="(-q)" />\n        <param name="quality_max" type="integer" label="Mask bases with quality higher than" \n               value="255" min="0" max="255" help="(-X)" />\n    </inputs>\n    <outputs>\n        <data name="output1" format="fasta" />\n    </outputs>\n    <tests>\n        <test>\n            <param name="input1" value="2.fastq"/>\n            <output name="output1" file="2.fasta"/>\n        </test>\n    </tests>\n    <help><![CDATA[\n        \nUsage:   seqtk seq [options] <in.fq>|<in.fa>\n\nOptions: -q INT    mask bases with quality lower than INT [0]\n         -X INT    mask bases with quality higher than INT [255]\n         -n CHAR   masked bases converted to CHAR; 0 for lowercase [0]\n         -l INT    number of residues per line; 0 for 2^32-1 [0]\n         -Q INT    quality shift: ASCII-INT gives base quality [33]\n         -s INT    random seed (effective with -f) [11]\n         -f FLOAT  sample FLOAT fraction of sequences [1]\n         -M FILE   mask regions in BED or name list FILE [null]\n         -L INT    drop sequences with length shorter than INT [0]\n         -c        mask complement region (effective with -M)\n         -r        reverse complement\n         -A        force FASTA output (discard quality)\n         -C        drop comments at the header lines\n         -N        drop sequences containing ambiguous bases\n         -1        output the 2n-1 reads only\n         -2        output the 2n reads only\n         -V        shift quality by \'(-Q) - 33\'\n         -U        convert all bases to uppercases\n\n\n    ]]></help>\n    <citations>\n        <citation type="bibtex">\n@misc{githubseqtk,\n  author = {LastTODO, FirstTODO},\n  year = {TODO},\n  title = {seqtk},\n  publisher = {GitHub},\n  journal = {GitHub repository},\n  url = {https://github.com/lh3/seqtk},\n}</citation>\n    </citations>\n</tool>
\n

条件参数

\n

以前的参数很简单,因为它们总是出现,现在考虑一下下面的参数。

\n
-M FILE   mask regions in BED or name list FILE [null]
\n

我们可以通过添加属性 optional ="true" 将该数据类型参数标记为可选。

\n
<param name="mask_regions" type="data" label="Mask regions in BED"\n       format="bed" help="(-M)" optional="true" />
\n

然后,不仅可以直接在命令块中使用 $mask_regions,还可以将其包装在 if 语句中(因为工具 XML 文件支持 Cheetah)。

\n
#if $mask_regions\n-M \'$mask_regions\'\n#end if
\n

接着,我们考虑这一组参数:

\n
-s INT    random seed (effective with -f) [11]\n-f FLOAT  sample FLOAT fraction of sequences [1]
\n

在这种情况下,只有在设置了样本参数的情况下,才能看到或使用 -s 随机种子参数。我们可以使用 conditional 条件块来表达这一点。

\n
<conditional name="sample">\n    <param name="sample_selector" type="boolean" label="Sample fraction of sequences" />\n    <when value="true">\n        <param name="fraction" label="Fraction" type="float" value="1.0"\n               help="(-f)" />\n        <param name="seed" label="Random seed" type="integer" value="11"\n               help="(-s)" />\n    </when>\n    <when value="false">\n    </when>\n</conditional>
\n

在命令块中,我们可以再次使用 if 语句包括这些参数。

\n
#if $sample.sample_selector\n-f $sample.fraction -s $sample.seed\n#end if
\n

注意,我们必须使用 sample. 的前缀来引用这个参数,因为它们是在 sample 的条件块内定义的。

\n

现在该工具的最新版本如下:

\n
<tool id="seqtk_seq" name="Convert to FASTA (seqtk)" version="0.1.0" python_template_version="3.5">\n    <requirements>\n        <requirement type="package" version="1.2">seqtk</requirement>\n    </requirements>\n    <command detect_errors="exit_code"><![CDATA[\n        seqtk seq\n              $shift_quality\n              -q $quality_min\n              -X $quality_max\n              #if $mask_regions\n                  -M \'$mask_regions\'\n              #end if\n              #if $sample.sample\n                  -f $sample.fraction\n                  -s $sample.seed\n              #end if\n              -a \'$input1\' > \'$output1\'\n    ]]></command>\n    <inputs>\n        <param type="data" name="input1" format="fastq" />\n        <param name="shift_quality" type="boolean" label="Shift quality" \n               truevalue="-V" falsevalue=""\n               help="shift quality by \'(-Q) - 33\' (-V)" />\n        <param name="quality_min" type="integer" label="Mask bases with quality lower than" \n               value="0" min="0" max="255" help="(-q)" />\n        <param name="quality_max" type="integer" label="Mask bases with quality higher than" \n               value="255" min="0" max="255" help="(-X)" />\n        <param name="mask_regions" type="data" label="Mask regions in BED" \n               format="bed" help="(-M)" optional="true" />\n        <conditional name="sample">\n            <param name="sample" type="boolean" label="Sample fraction of sequences" />\n            <when value="true">\n                <param name="fraction" label="Fraction" type="float" value="1.0"\n                       help="(-f)" />\n                <param name="seed" label="Random seed" type="integer" value="11"\n                       help="(-s)" />\n            </when>\n            <when value="false">\n            </when>\n        </conditional>\n    </inputs>\n    <outputs>\n        <data name="output1" format="fasta" />\n    </outputs>\n    <tests>\n        <test>\n            <param name="input1" value="2.fastq"/>\n            <output name="output1" file="2.fasta"/>\n        </test>\n    </tests>\n    <help><![CDATA[\n        \nUsage:   seqtk seq [options] <in.fq>|<in.fa>\n\nOptions: -q INT    mask bases with quality lower than INT [0]\n         -X INT    mask bases with quality higher than INT [255]\n         -n CHAR   masked bases converted to CHAR; 0 for lowercase [0]\n         -l INT    number of residues per line; 0 for 2^32-1 [0]\n         -Q INT    quality shift: ASCII-INT gives base quality [33]\n         -s INT    random seed (effective with -f) [11]\n         -f FLOAT  sample FLOAT fraction of sequences [1]\n         -M FILE   mask regions in BED or name list FILE [null]\n         -L INT    drop sequences with length shorter than INT [0]\n         -c        mask complement region (effective with -M)\n         -r        reverse complement\n         -A        force FASTA output (discard quality)\n         -C        drop comments at the header lines\n         -N        drop sequences containing ambiguous bases\n         -1        output the 2n-1 reads only\n         -2        output the 2n reads only\n         -V        shift quality by \'(-Q) - 33\'\n         -U        convert all bases to uppercases\n\n\n    ]]></help>\n    <citations>\n        <citation type="bibtex">\n@misc{githubseqtk,\n  author = {LastTODO, FirstTODO},\n  year = {TODO},\n  title = {seqtk},\n  publisher = {GitHub},\n  journal = {GitHub repository},\n  url = {https://github.com/lh3/seqtk},\n}</citation>\n    </citations>\n</tool>
\n

对于这样的工具,这些工具有很多选项,但在大多数情况下使用默认值是首选——一个常见的习惯用法是使用条件将参数分为简单部分和高级部分。

\n

使用惯用法,更新此工具后的 XML 如下所示:

\n
<tool id="seqtk_seq" name="Convert to FASTA (seqtk)" version="0.1.0" python_template_version="3.5">\n    <requirements>\n        <requirement type="package" version="1.2">seqtk</requirement>\n    </requirements>\n    <command detect_errors="exit_code"><![CDATA[\n        seqtk seq\n              #if $settings.advanced == "advanced"\n                  $settings.shift_quality\n                  -q $settings.quality_min\n                  -X $settings.quality_max\n                  #if $settings.mask_regions\n                      -M \'$settings.mask_regions\'\n                  #end if\n                  #if $settings.sample.sample\n                      -f $settings.sample.fraction\n                      -s $settings.sample.seed\n                  #end if\n              #end if\n              -a \'$input1\' > \'$output1\'\n    ]]></command>\n    <inputs>\n        <param type="data" name="input1" format="fastq" />\n        <conditional name="settings">\n            <param name="advanced" type="select" label="Specify advanced parameters">\n                <option value="simple" selected="true">No, use program defaults.</option>\n                <option value="advanced">Yes, see full parameter list.</option>\n            </param>\n            <when value="simple">\n            </when>\n            <when value="advanced">\n                <param name="shift_quality" type="boolean" label="Shift quality" \n                       truevalue="-V" falsevalue=""\n                       help="shift quality by \'(-Q) - 33\' (-V)" />\n                <param name="quality_min" type="integer" label="Mask bases with quality lower than" \n                       value="0" min="0" max="255" help="(-q)" />\n                <param name="quality_max" type="integer" label="Mask bases with quality higher than" \n                       value="255" min="0" max="255" help="(-X)" />\n                <param name="mask_regions" type="data" label="Mask regions in BED" \n                       format="bed" help="(-M)" optional="true" />\n                <conditional name="sample">\n                    <param name="sample" type="boolean" label="Sample fraction of sequences" />\n                    <when value="true">\n                        <param name="fraction" label="Fraction" type="float" value="1.0"\n                               help="(-f)" />\n                        <param name="seed" label="Random seed" type="integer" value="11"\n                               help="(-s)" />\n                    </when>\n                    <when value="false">\n                    </when>\n                </conditional>\n            </when>\n        </conditional>\n    </inputs>\n    <outputs>\n        <data name="output1" format="fasta" />\n    </outputs>\n    <tests>\n        <test>\n            <param name="input1" value="2.fastq"/>\n            <output name="output1" file="2.fasta"/>\n        </test>\n    </tests>\n    <help><![CDATA[\n        \nUsage:   seqtk seq [options] <in.fq>|<in.fa>\n\nOptions: -q INT    mask bases with quality lower than INT [0]\n         -X INT    mask bases with quality higher than INT [255]\n         -n CHAR   masked bases converted to CHAR; 0 for lowercase [0]\n         -l INT    number of residues per line; 0 for 2^32-1 [0]\n         -Q INT    quality shift: ASCII-INT gives base quality [33]\n         -s INT    random seed (effective with -f) [11]\n         -f FLOAT  sample FLOAT fraction of sequences [1]\n         -M FILE   mask regions in BED or name list FILE [null]\n         -L INT    drop sequences with length shorter than INT [0]\n         -c        mask complement region (effective with -M)\n         -r        reverse complement\n         -A        force FASTA output (discard quality)\n         -C        drop comments at the header lines\n         -N        drop sequences containing ambiguous bases\n         -1        output the 2n-1 reads only\n         -2        output the 2n reads only\n         -V        shift quality by \'(-Q) - 33\'\n         -U        convert all bases to uppercases\n\n\n    ]]></help>\n    <citations>\n        <citation type="bibtex">\n@misc{githubseqtk,\n  author = {LastTODO, FirstTODO},\n  year = {TODO},\n  title = {seqtk},\n  publisher = {GitHub},\n  journal = {GitHub repository},\n  url = {https://github.com/lh3/seqtk},\n}</citation>\n    </citations>\n</tool>
\n

脚本封装

\n

Tool Shed 上已经提供了许多常见的生物信息学应用程序,因此一项常见的开发任务是将各种复杂程度的脚本集成到 Galaxy 中。

\n

考虑以下小型 Perl 脚本。

\n
#!/usr/bin/perl -w\n\n# usage : perl toolExample.pl <FASTA file> <output file>\n\nopen (IN, "<$ARGV[0]");\nopen (OUT, ">$ARGV[1]");\nwhile (<IN>) {\n    chop;\n    if (m/^>/) {\n        s/^>//;\n        if ($. > 1) {\n            print OUT sprintf("%.3f", $gc/$length) . "\\n";\n        }\n        $gc = 0;\n        $length = 0;\n    } else {\n        ++$gc while m/[gc]/ig;\n        $length += length $_;\n    }\n}\nprint OUT sprintf("%.3f", $gc/$length) . "\\n";\nclose( IN );\nclose( OUT );
\n

可以按照以下步骤为此脚本构建 Galaxy 工具,并将脚本与工具 XML 文件本身放在同一目录中。这里的特殊值 $__ tool_directory__ 是指工具(即 xml 文件)所在的目录。

\n
<tool id="gc_content" name="Compute GC content">\n  <description>for each sequence in a file</description>\n  <command>perl \'$__tool_directory__/gc_content.pl\' \'$input\' output.tsv</command>\n  <inputs>\n    <param name="input" type="data" format="fasta" label="Source file"/>\n  </inputs>\n  <outputs>\n    <data name="output" format="tabular" from_work_dir="output.tsv" />\n  </outputs>\n  <help>\nThis tool computes GC content from a FASTA file.\n  </help>\n</tool>
\n

Macros 宏集

\n

如果您希望为单个相对简单的应用程序或脚本编写工具,则应跳过本节。如果您希望维护一系列相关工具——经验表明,您将意识到有很多重复的 XML 可以很好地做到这一点。Galaxy工具 XML 宏可以帮助减少这种重复。

\n

通过使用 --macros 标志,Planemo 的 tool_init 命令可用于生成适合工具套件的宏文件。我们看一下以前的 tool_init 命令的变体(唯一的区别是现在我们添加了 --macros 标志)。

\n
$ planemo tool_init --force \\\n                    --macros \\\n                    --id \'seqtk_seq\' \\\n                    --name \'Convert to FASTA (seqtk)\' \\\n                    --requirement seqtk@1.2 \\\n                    --example_command \'seqtk seq -A 2.fastq > 2.fasta\' \\\n                    --example_input 2.fastq \\\n                    --example_output 2.fasta \\\n                    --test_case \\\n                    --help_from_command \'seqtk seq\'
\n

这将在当前目录中产生两个文件( seqtk_seq.xmlmacros.xml),而不是一个。

\n
<tool id="seqtk_seq" name="Convert to FASTA (seqtk)" version="0.1.0" python_template_version="3.5">\n    <macros>\n        <import>macros.xml</import>\n    </macros>\n    <expand macro="requirements" />\n    <command detect_errors="exit_code"><![CDATA[\n        seqtk seq -A \'$input1\' > \'$output1\'\n    ]]></command>\n    <inputs>\n        <param type="data" name="input1" format="fastq" />\n    </inputs>\n    <outputs>\n        <data name="output1" format="fasta" />\n    </outputs>\n    <tests>\n        <test>\n            <param name="input1" value="2.fastq"/>\n            <output name="output1" file="2.fasta"/>\n        </test>\n    </tests>\n    <help><![CDATA[\n\nUsage:   seqtk seq [options] <in.fq>|<in.fa>\n\nOptions: -q INT    mask bases with quality lower than INT [0]\n         -X INT    mask bases with quality higher than INT [255]\n         -n CHAR   masked bases converted to CHAR; 0 for lowercase [0]\n         -l INT    number of residues per line; 0 for 2^32-1 [0]\n         -Q INT    quality shift: ASCII-INT gives base quality [33]\n         -s INT    random seed (effective with -f) [11]\n         -f FLOAT  sample FLOAT fraction of sequences [1]\n         -M FILE   mask regions in BED or name list FILE [null]\n         -L INT    drop sequences with length shorter than INT [0]\n         -c        mask complement region (effective with -M)\n         -r        reverse complement\n         -A        force FASTA output (discard quality)\n         -C        drop comments at the header lines\n         -N        drop sequences containing ambiguous bases\n         -1        output the 2n-1 reads only\n         -2        output the 2n reads only\n         -V        shift quality by \'(-Q) - 33\'\n         -U        convert all bases to uppercases\n         -S        strip of white spaces in sequences\n\n\n    ]]></help>\n    <expand macro="citations" />\n</tool>
\n
<macros>\n    <xml name="requirements">\n        <requirements>\n        <requirement type="package" version="1.2">seqtk</requirement>\n            <yield/>\n        </requirements>\n    </xml>\n    <xml name="citations">\n        <citations>\n            <yield />\n        </citations>\n    </xml>\n</macros>
\n

如您在上面的代码中所看到的,宏是可重用的 XML 块,它们使避免重复和保持 XML 简洁变得更加容易。

\n

参考资料

\n', 'author': {'login': 'shenweiyan'}, 'category': {'name': '3.1-Galaxy'}, 'labels': {'nodes': [{'name': '3.1.x-GalaxyOther'}]}, 'comments': {'nodes': []}}, {'title': '越来越难用的国内代码托管平台', 'number': 56, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/56', 'createdAt': '2024-02-02T03:26:02Z', 'lastEditedAt': '2024-02-04T00:48:19Z', 'updatedAt': '2024-02-04T00:48:19Z', 'body': '国内的代码平台对个人用户极其不友好,GitHub 可用的情况下,还是继续用着 GitHub 吧。\r\n\r\n\r\n\r\n## 码云\r\n\r\nGitee 的 Issues 永远都无法搜索内容 - ,感觉社区版本已经在摆烂了,现在他们的重点已经放在了企业版本,但是企业版本又难用的要死!\r\n\r\n## 扣钉\r\n\r\nCoding 现在的页面逻辑我是已经搞不明白了,注销的组织名称永远无法释放不说,在代码仓库更是连 Issues 都去掉了......\r\n\r\n## 极狐\r\n\r\n单是从体验上来说,背靠着 Gitlab 的 [极狐(GitLab)](https://gitlab.cn/) 其实做的还不错,虽然也还没有 APP。 \r\n- [极狐 GitLab 怎么样好不好_极狐 GitLab 优势有哪些-极狐 GitLab](https://gitlab.cn/is-it-any-good/) \r\n- [极狐 GitLab vs GitLab vs GitHub vs Gitee](https://gitlab.cn/comparison/) \r\n![gitlab-jh](https://shub.weiyan.tech/kgarden/2024/02/jihulab-vs-github-gitee.png)\r\n\r\n但是,现在问题来了,极狐从[2024年1月2日起开始要收费了](https://gitlab.cn/blog/2023/11/29/saas-adjustment/),这又是一个昙花一现可以放弃的托管平台,即使付费也总让人感觉这个平台套路不少。\r\n\r\n## 最后\r\n\r\n最后,对于国内的代码托管平台的一个感受 —— 对个人用户极其不友好,都热衷去倒腾企业的版本了,所以,GitHub 可用的情况下,还是继续用着 GitHub 吧;某些情况下登录不上 GitHub 了,国内的 GitCode 作为备用暂时凑合着用吧;至于 Gitee/Coding/Jihulab,还是不要浪费时间去折腾了。', 'bodyText': '国内的代码平台对个人用户极其不友好,GitHub 可用的情况下,还是继续用着 GitHub 吧。\n\n码云\nGitee 的 Issues 永远都无法搜索内容 - https://gitee.com/oschina/git-osc/issues/I7T4W6,感觉社区版本已经在摆烂了,现在他们的重点已经放在了企业版本,但是企业版本又难用的要死!\n扣钉\nCoding 现在的页面逻辑我是已经搞不明白了,注销的组织名称永远无法释放不说,在代码仓库更是连 Issues 都去掉了......\n极狐\n单是从体验上来说,背靠着 Gitlab 的 极狐(GitLab) 其实做的还不错,虽然也还没有 APP。\n\n极狐 GitLab 怎么样好不好_极狐 GitLab 优势有哪些-极狐 GitLab\n极狐 GitLab vs GitLab vs GitHub vs Gitee\n\n\n但是,现在问题来了,极狐从2024年1月2日起开始要收费了,这又是一个昙花一现可以放弃的托管平台,即使付费也总让人感觉这个平台套路不少。\n最后\n最后,对于国内的代码托管平台的一个感受 —— 对个人用户极其不友好,都热衷去倒腾企业的版本了,所以,GitHub 可用的情况下,还是继续用着 GitHub 吧;某些情况下登录不上 GitHub 了,国内的 GitCode 作为备用暂时凑合着用吧;至于 Gitee/Coding/Jihulab,还是不要浪费时间去折腾了。', 'bodyHTML': '

国内的代码平台对个人用户极其不友好,GitHub 可用的情况下,还是继续用着 GitHub 吧。

\n\n

码云

\n

Gitee 的 Issues 永远都无法搜索内容 - https://gitee.com/oschina/git-osc/issues/I7T4W6,感觉社区版本已经在摆烂了,现在他们的重点已经放在了企业版本,但是企业版本又难用的要死!

\n

扣钉

\n

Coding 现在的页面逻辑我是已经搞不明白了,注销的组织名称永远无法释放不说,在代码仓库更是连 Issues 都去掉了......

\n

极狐

\n

单是从体验上来说,背靠着 Gitlab 的 极狐(GitLab) 其实做的还不错,虽然也还没有 APP。

\n\n

但是,现在问题来了,极狐从2024年1月2日起开始要收费了,这又是一个昙花一现可以放弃的托管平台,即使付费也总让人感觉这个平台套路不少。

\n

最后

\n

最后,对于国内的代码托管平台的一个感受 —— 对个人用户极其不友好,都热衷去倒腾企业的版本了,所以,GitHub 可用的情况下,还是继续用着 GitHub 吧;某些情况下登录不上 GitHub 了,国内的 GitCode 作为备用暂时凑合着用吧;至于 Gitee/Coding/Jihulab,还是不要浪费时间去折腾了。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '从公众号到个人独立站点', 'number': 55, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/55', 'createdAt': '2024-01-25T12:28:05Z', 'lastEditedAt': '2024-01-25T12:29:50Z', 'updatedAt': '2024-01-25T12:29:50Z', 'body': '从 2023 年下半年以来 "**BioIT爱好者**" 这个公众号基本上很少更新了,这一点在《[公众号许久没有更新了](https://github.com/shenweiyan/Knowledge-Garden/discussions/28)》就提到过,现在唯一有所区别的是在 [GitHub Discussions](https://github.com/shenweiyan/Knowledge-Garden/discussions/) 的基础上又多了一个个人的独立站点。\r\n\r\n\r\n\r\n![weiyan-cc-home](https://shub.weiyan.tech/kgarden/2024/01/weiyan-cc-home.png)\r\n\r\n![weiyan-cc-hblog](https://shub.weiyan.tech/kgarden/2024/01/weiyan-cc-blog.png)\r\n\r\n全面拥抱 GitHub 的感觉真的很好,加上手机 APP 的加持,更加如虎添翼。回归了最原始 markdown 的编辑和写作,也终于不用再担心在《[富文本编辑器与 md 语法的一些困惑](https://github.com/shenweiyan/Knowledge-Garden/discussions/26)》中所顾虑的问题。\r\n\r\n从 GitHub 到选择 Material for MkDocs 作为个人博客+文档独立站点,有很多的影响因素,但数据可控算是比较核心的一个出发点。这半年来混迹 GitHub 的确也收获良多,发现了很多[有意思的博客和站点](https://github.com/shenweiyan/Knowledge-Garden/discussions/41),学习到了很多优秀的项目。很多时候阅读别人的博客(站点),总能发现一些好玩的人和事物。\r\n\r\n2023 年被[椒盐豆豉](https://blog.douchi.space/)的一篇《[2023 年了你为什么需要写博客](https://blog.douchi.space/2023-why-you-need-a-blog/)》所吸引,尤其是 "博客是赛博空间的另一个你,也能反过来定义你" 这一句,写出了很多心声。\r\n\r\n> 比较反感 "个人品牌" 这个过于商业化的说法,不写技术不写学术的非实名博客甚至起不到简历作用。但它确是比简历更 "像个人",比碎片化社交网络更全面展现我是怎样一个人的网络门面。当然这是我这个博客的用法,网上靠博客经营自己品牌的也比比皆是。总之,内容的自由度和高度的定制化让博客可以成为任何你想让它成为的东西。反之,博客写的久了,发现 "写博客" 也已经成为了自己(不只是线上) identity 的一部分——毕竟这是很多人认识我的渠道,也重塑了我的一部分自我认知。\r\n\r\n虽然期间尝试过《[飞书文档初体验](https://github.com/shenweiyan/Knowledge-Garden/discussions/11)》,从国内版本的飞书到 LarkSuite,但终究不如 GitHub + Material for MkDocs 组合来得顺畅。GitHub 也好,飞书也罢,各种五花八门的奇淫巧技和折腾组合,总有能玩出花来的一波人,找到自己喜欢的并持之以恒就已经足够。\r\n\r\n趁着今天有时间,在公众号同步了这一篇,希望我们不忘初心,做到最好。', 'bodyText': '从 2023 年下半年以来 "BioIT爱好者" 这个公众号基本上很少更新了,这一点在《公众号许久没有更新了》就提到过,现在唯一有所区别的是在 GitHub Discussions 的基础上又多了一个个人的独立站点。\n\n\n\n全面拥抱 GitHub 的感觉真的很好,加上手机 APP 的加持,更加如虎添翼。回归了最原始 markdown 的编辑和写作,也终于不用再担心在《富文本编辑器与 md 语法的一些困惑》中所顾虑的问题。\n从 GitHub 到选择 Material for MkDocs 作为个人博客+文档独立站点,有很多的影响因素,但数据可控算是比较核心的一个出发点。这半年来混迹 GitHub 的确也收获良多,发现了很多有意思的博客和站点,学习到了很多优秀的项目。很多时候阅读别人的博客(站点),总能发现一些好玩的人和事物。\n2023 年被椒盐豆豉的一篇《2023 年了你为什么需要写博客》所吸引,尤其是 "博客是赛博空间的另一个你,也能反过来定义你" 这一句,写出了很多心声。\n\n比较反感 "个人品牌" 这个过于商业化的说法,不写技术不写学术的非实名博客甚至起不到简历作用。但它确是比简历更 "像个人",比碎片化社交网络更全面展现我是怎样一个人的网络门面。当然这是我这个博客的用法,网上靠博客经营自己品牌的也比比皆是。总之,内容的自由度和高度的定制化让博客可以成为任何你想让它成为的东西。反之,博客写的久了,发现 "写博客" 也已经成为了自己(不只是线上) identity 的一部分——毕竟这是很多人认识我的渠道,也重塑了我的一部分自我认知。\n\n虽然期间尝试过《飞书文档初体验》,从国内版本的飞书到 LarkSuite,但终究不如 GitHub + Material for MkDocs 组合来得顺畅。GitHub 也好,飞书也罢,各种五花八门的奇淫巧技和折腾组合,总有能玩出花来的一波人,找到自己喜欢的并持之以恒就已经足够。\n趁着今天有时间,在公众号同步了这一篇,希望我们不忘初心,做到最好。', 'bodyHTML': '

从 2023 年下半年以来 "BioIT爱好者" 这个公众号基本上很少更新了,这一点在《公众号许久没有更新了》就提到过,现在唯一有所区别的是在 GitHub Discussions 的基础上又多了一个个人的独立站点。

\n\n

weiyan-cc-home

\n

weiyan-cc-hblog

\n

全面拥抱 GitHub 的感觉真的很好,加上手机 APP 的加持,更加如虎添翼。回归了最原始 markdown 的编辑和写作,也终于不用再担心在《富文本编辑器与 md 语法的一些困惑》中所顾虑的问题。

\n

从 GitHub 到选择 Material for MkDocs 作为个人博客+文档独立站点,有很多的影响因素,但数据可控算是比较核心的一个出发点。这半年来混迹 GitHub 的确也收获良多,发现了很多有意思的博客和站点,学习到了很多优秀的项目。很多时候阅读别人的博客(站点),总能发现一些好玩的人和事物。

\n

2023 年被椒盐豆豉的一篇《2023 年了你为什么需要写博客》所吸引,尤其是 "博客是赛博空间的另一个你,也能反过来定义你" 这一句,写出了很多心声。

\n
\n

比较反感 "个人品牌" 这个过于商业化的说法,不写技术不写学术的非实名博客甚至起不到简历作用。但它确是比简历更 "像个人",比碎片化社交网络更全面展现我是怎样一个人的网络门面。当然这是我这个博客的用法,网上靠博客经营自己品牌的也比比皆是。总之,内容的自由度和高度的定制化让博客可以成为任何你想让它成为的东西。反之,博客写的久了,发现 "写博客" 也已经成为了自己(不只是线上) identity 的一部分——毕竟这是很多人认识我的渠道,也重塑了我的一部分自我认知。

\n
\n

虽然期间尝试过《飞书文档初体验》,从国内版本的飞书到 LarkSuite,但终究不如 GitHub + Material for MkDocs 组合来得顺畅。GitHub 也好,飞书也罢,各种五花八门的奇淫巧技和折腾组合,总有能玩出花来的一波人,找到自己喜欢的并持之以恒就已经足够。

\n

趁着今天有时间,在公众号同步了这一篇,希望我们不忘初心,做到最好。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': [{'name': '公众号'}]}, 'comments': {'nodes': []}}, {'title': 'Mkdocs material 使用自定义 slug 和 url', 'number': 54, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/54', 'createdAt': '2024-01-23T06:53:45Z', 'lastEditedAt': None, 'updatedAt': '2024-01-23T06:53:46Z', 'body': 'Mkdocs material 默认使用目录+文件名作为 post 展示的 URL,如果目录名/文件名太长的话,你的 URL 就会显得非常长。尤其是当你从浏览器地址栏中复制某一篇文档的链接时候,如果你的 URL 同时包含了中文,URL 转码后会导致你复制后粘贴的链接变得更加长。\r\n\r\n\r\n\r\nMkdocs material 目前我是没看到有什么具体的插件解决这个问题,只不过有人在 [squidfunk/mkdocs-material#5161](https://github.com/squidfunk/mkdocs-material/discussions/5161) 基于 hook 提供了一个解决的方案。这个方案基本上能满足我们的需求,但也有一些限制。\r\n\r\n- slug 必须是不能以 `/` 作为开头,且必须以 `/` 作为结尾。\r\n- 可能会导致内部链接引用出现问题。\r\n- 会重复读取任务,如果文件非常多,会降低相对于文件量的整体性能。', 'bodyText': 'Mkdocs material 默认使用目录+文件名作为 post 展示的 URL,如果目录名/文件名太长的话,你的 URL 就会显得非常长。尤其是当你从浏览器地址栏中复制某一篇文档的链接时候,如果你的 URL 同时包含了中文,URL 转码后会导致你复制后粘贴的链接变得更加长。\n\nMkdocs material 目前我是没看到有什么具体的插件解决这个问题,只不过有人在 squidfunk/mkdocs-material#5161 基于 hook 提供了一个解决的方案。这个方案基本上能满足我们的需求,但也有一些限制。\n\nslug 必须是不能以 / 作为开头,且必须以 / 作为结尾。\n可能会导致内部链接引用出现问题。\n会重复读取任务,如果文件非常多,会降低相对于文件量的整体性能。', 'bodyHTML': '

Mkdocs material 默认使用目录+文件名作为 post 展示的 URL,如果目录名/文件名太长的话,你的 URL 就会显得非常长。尤其是当你从浏览器地址栏中复制某一篇文档的链接时候,如果你的 URL 同时包含了中文,URL 转码后会导致你复制后粘贴的链接变得更加长。

\n\n

Mkdocs material 目前我是没看到有什么具体的插件解决这个问题,只不过有人在 squidfunk/mkdocs-material#5161 基于 hook 提供了一个解决的方案。这个方案基本上能满足我们的需求,但也有一些限制。

\n
    \n
  • slug 必须是不能以 / 作为开头,且必须以 / 作为结尾。
  • \n
  • 可能会导致内部链接引用出现问题。
  • \n
  • 会重复读取任务,如果文件非常多,会降低相对于文件量的整体性能。
  • \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'Mkdocs material 对指定页面隐藏 H1 标题', 'number': 53, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/53', 'createdAt': '2024-01-19T03:42:11Z', 'lastEditedAt': None, 'updatedAt': '2024-01-19T03:42:12Z', 'body': '主要记录一下在 Mkdocs material 中对指定页面隐藏标题,尤其是指在 Home 页面把 H1 级别的标题隐藏的一些解决方法。\r\n\r\n\r\n\r\n## 背景\r\n\r\n对于一些特定的页面,不想显示顶级的标题,尤其是 H1 标题。Mkdocs material 讨论区给出了几个方案:\r\n\r\n1. 内联 CSS 的方法,参考 [squidfunk/mkdocs-material#2163](https://github.com/squidfunk/mkdocs-material/issues/2163)。 \r\n 这个方法的确能解决隐藏当前页面的 H1 标题,但**同时会把搜索栏搜索结果的 H1 标题给隐藏了**。有点治标不治本!\r\n2. 自定义页面模板,参考 [squidfunk/mkdocs-material#6185](https://github.com/squidfunk/mkdocs-material/discussions/6185)。\r\n 这个参考的讨论里面没有给出具体的解决方法,本文章来详细介绍一下。\r\n\r\n## 创建模板\r\n\r\n首先,在 `overrides` 目录下创建一个名为 `home.html` 的文件(文件名可以随意命名),内容可以参考 [`blog.html`](https://github.com/squidfunk/mkdocs-material/blob/master/material/templates/blog.html) 的内容。\r\n```\r\n{% extends "base.html" %}\r\n{% block htmltitle %}\r\n {% if page.meta and page.meta.title %}\r\n {{ page.meta.title }}\r\n {% elif page.title and not page.is_homepage %}\r\n {{ page.title | striptags }}\r\n {% else %}\r\n {{ config.site_name }}\r\n {% endif %}\r\n{% endblock %}\r\n\r\n{% block container %}\r\n
\r\n
\r\n {% block content %}\r\n {% include "partials/mycontent.html" %}\r\n {% endblock %}\r\n
\r\n
\r\n{% endblock %}\r\n\r\n{% block extrahead %}\r\n \r\n \r\n{% endblock %}\r\n```\r\n\r\n第二,创建 `overrides/partials/mycontent.html` 文件,内容参考 [`content.html`](https://github.com/squidfunk/mkdocs-material/blob/master/material/templates/partials/content.html) 文件,注意把 h1 的元素注释掉。\r\n```\r\n{#-\r\n This file was automatically generated - do not edit\r\n-#}\r\n{% if "material/tags" in config.plugins and tags %}\r\n {% include "partials/tags.html" %}\r\n{% endif %}\r\n{% include "partials/actions.html" %}\r\n{% if "\\x3ch1" not in page.content %}\r\n \r\n{% endif %}\r\n{{ page.content }}\r\n{% include "partials/source-file.html" %}\r\n{% include "partials/feedback.html" %}\r\n{% include "partials/comments.html" %}\r\n```\r\n\r\n## 在页面中使用模板\r\n\r\n例如,在个人站点的主页文件 `docs/index.md` 中头部,使用 `template` 指定使用的模板。\r\n```\r\n---\r\ntitle: 维燕的知识花园\r\ntemplate: home.html\r\n---\r\n```\r\n\r\n最后,重新启动 mkdocs 就可以看到对应页面 H1 隐藏后的效果。\r\n', 'bodyText': '主要记录一下在 Mkdocs material 中对指定页面隐藏标题,尤其是指在 Home 页面把 H1 级别的标题隐藏的一些解决方法。\n\n背景\n对于一些特定的页面,不想显示顶级的标题,尤其是 H1 标题。Mkdocs material 讨论区给出了几个方案:\n\n内联 CSS 的方法,参考 squidfunk/mkdocs-material#2163。\n这个方法的确能解决隐藏当前页面的 H1 标题,但同时会把搜索栏搜索结果的 H1 标题给隐藏了。有点治标不治本!\n自定义页面模板,参考 squidfunk/mkdocs-material#6185。\n这个参考的讨论里面没有给出具体的解决方法,本文章来详细介绍一下。\n\n创建模板\n首先,在 overrides 目录下创建一个名为 home.html 的文件(文件名可以随意命名),内容可以参考 blog.html 的内容。\n{% extends "base.html" %}\n{% block htmltitle %}\n {% if page.meta and page.meta.title %}\n {{ page.meta.title }}\n {% elif page.title and not page.is_homepage %}\n {{ page.title | striptags }}\n {% else %}\n {{ config.site_name }}\n {% endif %}\n{% endblock %}\n\n{% block container %}\n
\n
\n {% block content %}\n {% include "partials/mycontent.html" %}\n {% endblock %}\n
\n
\n{% endblock %}\n\n{% block extrahead %}\n \n \n{% endblock %}\n\n第二,创建 overrides/partials/mycontent.html 文件,内容参考 content.html 文件,注意把 h1 的元素注释掉。\n{#-\n This file was automatically generated - do not edit\n-#}\n{% if "material/tags" in config.plugins and tags %}\n {% include "partials/tags.html" %}\n{% endif %}\n{% include "partials/actions.html" %}\n{% if "\\x3ch1" not in page.content %}\n \n{% endif %}\n{{ page.content }}\n{% include "partials/source-file.html" %}\n{% include "partials/feedback.html" %}\n{% include "partials/comments.html" %}\n\n在页面中使用模板\n例如,在个人站点的主页文件 docs/index.md 中头部,使用 template 指定使用的模板。\n---\ntitle: 维燕的知识花园\ntemplate: home.html\n---\n\n最后,重新启动 mkdocs 就可以看到对应页面 H1 隐藏后的效果。', 'bodyHTML': '

主要记录一下在 Mkdocs material 中对指定页面隐藏标题,尤其是指在 Home 页面把 H1 级别的标题隐藏的一些解决方法。

\n\n

背景

\n

对于一些特定的页面,不想显示顶级的标题,尤其是 H1 标题。Mkdocs material 讨论区给出了几个方案:

\n
    \n
  1. 内联 CSS 的方法,参考 squidfunk/mkdocs-material#2163
    \n这个方法的确能解决隐藏当前页面的 H1 标题,但同时会把搜索栏搜索结果的 H1 标题给隐藏了。有点治标不治本!
  2. \n
  3. 自定义页面模板,参考 squidfunk/mkdocs-material#6185
    \n这个参考的讨论里面没有给出具体的解决方法,本文章来详细介绍一下。
  4. \n
\n

创建模板

\n

首先,在 overrides 目录下创建一个名为 home.html 的文件(文件名可以随意命名),内容可以参考 blog.html 的内容。

\n
{% extends "base.html" %}\n{% block htmltitle %}\n      {% if page.meta and page.meta.title %}\n        <title>{{ page.meta.title }}</title>\n      {% elif page.title and not page.is_homepage %}\n        <title>{{ page.title | striptags }}</title>\n      {% else %}\n        <title>{{ config.site_name }}</title>\n      {% endif %}\n{% endblock %}\n\n{% block container %}\n    <div class="md-content" data-md-component="content">\n      <article class="md-content__inner md-typeset">\n        {% block content %}\n          {% include "partials/mycontent.html" %}\n        {% endblock %}\n      </article>\n    </div>\n{% endblock %}\n\n{% block extrahead %}\n      <!--style>.md-typeset h1,.md-content__button {display:none !important}; </style-->\n      <style>.md-header__topic {font-weight:700 !important}</style>\n{% endblock %}\n
\n

第二,创建 overrides/partials/mycontent.html 文件,内容参考 content.html 文件,注意把 h1 的元素注释掉。

\n
{#-\n  This file was automatically generated - do not edit\n-#}\n{% if "material/tags" in config.plugins and tags %}\n  {% include "partials/tags.html" %}\n{% endif %}\n{% include "partials/actions.html" %}\n{% if "\\x3ch1" not in page.content %}\n  <!--h1>{{ page.title | d(config.site_name, true)}}</h1-->\n{% endif %}\n{{ page.content }}\n{% include "partials/source-file.html" %}\n{% include "partials/feedback.html" %}\n{% include "partials/comments.html" %}\n
\n

在页面中使用模板

\n

例如,在个人站点的主页文件 docs/index.md 中头部,使用 template 指定使用的模板。

\n
---\ntitle: 维燕的知识花园\ntemplate: home.html\n---\n
\n

最后,重新启动 mkdocs 就可以看到对应页面 H1 隐藏后的效果。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'MkDocs Material 的一些使用与问题汇总', 'number': 52, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/52', 'createdAt': '2024-01-18T07:51:11Z', 'lastEditedAt': None, 'updatedAt': '2024-01-18T07:51:12Z', 'body': '记录一下 MkDocs Material 在使用过程中遇到的一些问题。\r\n\r\n\r\n\r\n1. 如何避免锚点链接的非英文字符转换成数字 \r\n - [How to disable converting non-english header links to numbers?#4682](https://github.com/squidfunk/mkdocs-material/discussions/4682)', 'bodyText': '记录一下 MkDocs Material 在使用过程中遇到的一些问题。\n\n\n如何避免锚点链接的非英文字符转换成数字\n\nHow to disable converting non-english header links to numbers?#4682', 'bodyHTML': '

记录一下 MkDocs Material 在使用过程中遇到的一些问题。

\n\n
    \n
  1. 如何避免锚点链接的非英文字符转换成数字\n\n
  2. \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'MkDocs 主题 awesome-pages 使用', 'number': 51, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/51', 'createdAt': '2024-01-11T09:24:34Z', 'lastEditedAt': '2024-01-12T02:12:55Z', 'updatedAt': '2024-01-12T02:12:55Z', 'body': '很长一段时间都在使用 [mkdocs_include_dir_to_nav](https://github.com/mysiki/mkdocs_include_dir_to_nav) 这个插件来自动包含目录下的所有 md 文件,但随着新需求的出现 —— **如何给某一个指定的子目录使用 `reverse_sort_file`,即升序排列展示子目录相应的 markdown 内容**。这才开始接触到 [MkDocs Awesome Pages Plugin](https://github.com/lukasgeiter/mkdocs-awesome-pages-plugin) 这个插件。\r\n\r\n\r\n\r\n## 开始\r\n\r\n从 GitHub 可以很直观看到的是 [mkdocs_include_dir_to_nav](https://github.com/mysiki/mkdocs_include_dir_to_nav) 自从 2022-05-01 更新了 [V1.2.0](https://github.com/mysiki/mkdocs_include_dir_to_nav/releases/tag/v1.2.0) 版本后基本就已经停止了更新,Star 也才 20 多人。 \r\n![mkdocs-include-dir-to-nav](https://shub.weiyan.tech/kgarden/2024/01/mkdocs-include-dir-to-nav.png)\r\n\r\n反而是 [MkDocs Awesome Pages Plugin](https://github.com/lukasgeiter/mkdocs-awesome-pages-plugin) 一直保持着非常积极的更新频率,而且维护者和关注和使用用户也远远比 [mkdocs_include_dir_to_nav](https://github.com/mysiki/mkdocs_include_dir_to_nav) 多得多。 \r\n![mkdocs-awesome-pages-plugin](https://shub.weiyan.tech/kgarden/2024/01/mkdocs-awesome-pages-plugin.png)\r\n\r\n于是,开始着入手 [MkDocs Awesome Pages Plugin](https://github.com/lukasgeiter/mkdocs-awesome-pages-plugin)。不得不说,Awesome-Pages 这个插件的功能很强大,可以很好解决我"指定子目录自定义文档排序"的需求。但不可否认的是 Awesome-Pages 的文档写的的确有点糙,不认真看还真不知道应该如何上手,这也是花费我最多时间的地方。\r\n\r\n## 使用\r\n\r\n使用 [MkDocs Awesome Pages Plugin](https://github.com/lukasgeiter/mkdocs-awesome-pages-plugin) 有两个很重要的前提:\r\n\r\n1. 如果你在 `mkdocs.yml` 定义了 `nav` 或 `pages` 条目,则此插件不会执行任何操作。要使用该插件列出的功能,我们必须完全删除该条目或向其中添加 `...` 条目 ([add a `...` entry to it](https://github.com/lukasgeiter/mkdocs-awesome-pages-plugin?tab=readme-ov-file#combine-custom-navigation--file-structure))。\r\n2. 自定义导航时,在目录(或者子目录)中创建一个名为 `.pages` 的文件时,使用 `nav` 属性只能自定义**该级别的导航**!然后,按照文件和子目录在导航中出现的顺序列出文件和子目录。\r\n\r\n```\r\ndocs/\r\n├── README.md\r\n├── dirNamedA\r\n│ ├── dirA-page01.md\r\n│ ├── dirA-page02.md\r\n│ └── subDirNamedA1\r\n│ │ ├── subDirA1-page01.md\r\n│ │ └── subDirA1-page02.md\r\n│ └── subDirNamedA2\r\n│ ├── subDirA2-page01.md\r\n│ └── subDirA2-page02.md\r\n├── dirNamedB\r\n│ ├── dirB-page01.md\r\n│ ├── dirB-page02.md\r\n│ └── subDirNamedB1\r\n│ ├── subDirB1-page01.md\r\n│ └── subDirB1-page02.md\r\n└── emptyDir\r\n```\r\n\r\n这就发现了 [MkDocs Awesome Pages Plugin](https://github.com/lukasgeiter/mkdocs-awesome-pages-plugin) 和 MkDocs 、[mkdocs_include_dir_to_nav](https://github.com/mysiki/mkdocs_include_dir_to_nav) 在设置 navigation 时候的区别:[MkDocs Awesome Pages Plugin](https://github.com/lukasgeiter/mkdocs-awesome-pages-plugin) 的 `nav` 属性只能自定义**该级别的导航**!即无法只通过一个 `.pages` 实现所有目录+子目录的 navigation 排序配置。\r\n\r\n所以,最好的做法就是在 `docs` 目录下(包含 `docs`) 给每个目录增加一个 `.pages` 文件,用于控制当前目录的所有子目录(或者 Posts) 的排序和展示。\r\n\r\n', 'bodyText': '很长一段时间都在使用 mkdocs_include_dir_to_nav 这个插件来自动包含目录下的所有 md 文件,但随着新需求的出现 —— 如何给某一个指定的子目录使用 reverse_sort_file,即升序排列展示子目录相应的 markdown 内容。这才开始接触到 MkDocs Awesome Pages Plugin 这个插件。\n\n开始\n从 GitHub 可以很直观看到的是 mkdocs_include_dir_to_nav 自从 2022-05-01 更新了 V1.2.0 版本后基本就已经停止了更新,Star 也才 20 多人。\n\n反而是 MkDocs Awesome Pages Plugin 一直保持着非常积极的更新频率,而且维护者和关注和使用用户也远远比 mkdocs_include_dir_to_nav 多得多。\n\n于是,开始着入手 MkDocs Awesome Pages Plugin。不得不说,Awesome-Pages 这个插件的功能很强大,可以很好解决我"指定子目录自定义文档排序"的需求。但不可否认的是 Awesome-Pages 的文档写的的确有点糙,不认真看还真不知道应该如何上手,这也是花费我最多时间的地方。\n使用\n使用 MkDocs Awesome Pages Plugin 有两个很重要的前提:\n\n如果你在 mkdocs.yml 定义了 nav 或 pages 条目,则此插件不会执行任何操作。要使用该插件列出的功能,我们必须完全删除该条目或向其中添加 ... 条目 (add a ... entry to it)。\n自定义导航时,在目录(或者子目录)中创建一个名为 .pages 的文件时,使用 nav 属性只能自定义该级别的导航!然后,按照文件和子目录在导航中出现的顺序列出文件和子目录。\n\ndocs/\n├── README.md\n├── dirNamedA\n│ ├── dirA-page01.md\n│ ├── dirA-page02.md\n│ └── subDirNamedA1\n│ │ ├── subDirA1-page01.md\n│ │ └── subDirA1-page02.md\n│ └── subDirNamedA2\n│ ├── subDirA2-page01.md\n│ └── subDirA2-page02.md\n├── dirNamedB\n│ ├── dirB-page01.md\n│ ├── dirB-page02.md\n│ └── subDirNamedB1\n│ ├── subDirB1-page01.md\n│ └── subDirB1-page02.md\n└── emptyDir\n\n这就发现了 MkDocs Awesome Pages Plugin 和 MkDocs 、mkdocs_include_dir_to_nav 在设置 navigation 时候的区别:MkDocs Awesome Pages Plugin 的 nav 属性只能自定义该级别的导航!即无法只通过一个 .pages 实现所有目录+子目录的 navigation 排序配置。\n所以,最好的做法就是在 docs 目录下(包含 docs) 给每个目录增加一个 .pages 文件,用于控制当前目录的所有子目录(或者 Posts) 的排序和展示。', 'bodyHTML': '

很长一段时间都在使用 mkdocs_include_dir_to_nav 这个插件来自动包含目录下的所有 md 文件,但随着新需求的出现 —— 如何给某一个指定的子目录使用 reverse_sort_file,即升序排列展示子目录相应的 markdown 内容。这才开始接触到 MkDocs Awesome Pages Plugin 这个插件。

\n\n

开始

\n

从 GitHub 可以很直观看到的是 mkdocs_include_dir_to_nav 自从 2022-05-01 更新了 V1.2.0 版本后基本就已经停止了更新,Star 也才 20 多人。
\nmkdocs-include-dir-to-nav

\n

反而是 MkDocs Awesome Pages Plugin 一直保持着非常积极的更新频率,而且维护者和关注和使用用户也远远比 mkdocs_include_dir_to_nav 多得多。
\nmkdocs-awesome-pages-plugin

\n

于是,开始着入手 MkDocs Awesome Pages Plugin。不得不说,Awesome-Pages 这个插件的功能很强大,可以很好解决我"指定子目录自定义文档排序"的需求。但不可否认的是 Awesome-Pages 的文档写的的确有点糙,不认真看还真不知道应该如何上手,这也是花费我最多时间的地方。

\n

使用

\n

使用 MkDocs Awesome Pages Plugin 有两个很重要的前提:

\n
    \n
  1. 如果你在 mkdocs.yml 定义了 navpages 条目,则此插件不会执行任何操作。要使用该插件列出的功能,我们必须完全删除该条目或向其中添加 ... 条目 (add a ... entry to it)。
  2. \n
  3. 自定义导航时,在目录(或者子目录)中创建一个名为 .pages 的文件时,使用 nav 属性只能自定义该级别的导航!然后,按照文件和子目录在导航中出现的顺序列出文件和子目录。
  4. \n
\n
docs/\n├── README.md\n├── dirNamedA\n│   ├── dirA-page01.md\n│   ├── dirA-page02.md\n│   └── subDirNamedA1\n│   │   ├── subDirA1-page01.md\n│   │   └── subDirA1-page02.md\n│   └── subDirNamedA2\n│       ├── subDirA2-page01.md\n│       └── subDirA2-page02.md\n├── dirNamedB\n│   ├── dirB-page01.md\n│   ├── dirB-page02.md\n│   └── subDirNamedB1\n│       ├── subDirB1-page01.md\n│       └── subDirB1-page02.md\n└── emptyDir\n
\n

这就发现了 MkDocs Awesome Pages Plugin 和 MkDocs 、mkdocs_include_dir_to_nav 在设置 navigation 时候的区别:MkDocs Awesome Pages Pluginnav 属性只能自定义该级别的导航!即无法只通过一个 .pages 实现所有目录+子目录的 navigation 排序配置。

\n

所以,最好的做法就是在 docs 目录下(包含 docs) 给每个目录增加一个 .pages 文件,用于控制当前目录的所有子目录(或者 Posts) 的排序和展示。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '2023 年年终总结', 'number': 50, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/50', 'createdAt': '2024-01-10T05:34:20Z', 'lastEditedAt': '2024-01-10T09:10:58Z', 'updatedAt': '2024-01-10T09:10:58Z', 'body': '本来没想着写年终总结 —— 主要是最近对于码字没太多的欲望,但翻到了 2021/2022 的一些年终记录,也看了不少其他网友博主 2023 年的总结,所以对自己说,还是写一写吧。\r\n\r\n2023 年对个人来说是变动的一年,这个变动主要体现在工作上。反观生活,除去家庭的一些琐事基本上也就是波澜不惊的一个状态。\r\n\r\n\r\n\r\n## 工作\r\n\r\n2023 年工作最大的变动之一就是公司搬迁新的厂区。随之而来是上下班通勤的变更,这一切让原本相对充裕的时间变得更加紧凑。但时间是最大的习惯,久而久之这就成了生活的一部分,朝九晚五体现的淋漓尽致。\r\n\r\n第二个变动最大的是新办公地点新办公规章。这一点影响很大,以至于让我不得不放弃了很多以前形成的一部分工具习惯,转身去重新接纳一些新的工具和平台。于是,有了现在的[个人知识站点](https://weiyan.cc),有了[飞书的使用体验](https://www.weiyan.cc/blog/2023/10/24/discussion-11/),GitHub 更是一瞬间成为了个人最常逛和依赖的平台 —— 这也让我重新认识了这个平台的强大和无可替代。 \r\n

\r\n github-contributions-2023\r\n

\r\n\r\n职业方向上探索了一把 AI,浅尝辄止又摸不着门道;mRNA 到 Protein 的优化道路上才刚刚看到入口,任重道远;只能背靠着老本行,在不断优化的道路上踉踉跄跄走着。\r\n\r\n职业生涯的道路上人来人往,铁打的营盘流水的兵,走了就走了,无需留念。\r\n\r\n## 生活\r\n\r\n生活上其实没什么太多说的,感觉到微妙变化的是比以前更加注意到自己和身边人的健康问题了。从老婆孩子,到母亲的腰椎问题,再到自己,再加上这一年的流感、肺炎(尤其是支原体肺炎),2023 年在健康这个问题上的确投入了很大的一部分时间和精力。\r\n\r\n家庭琐事上,家人彼此磕磕碰碰的事情总会有,生活无律,人生无常,我们更需要的是相互之间相互理解与包容。对于老婆和孩子,需要更多的关心和陪伴。\r\n\r\n运动这件事情上,基本还能保持着每周至少一场羽毛球,这是值得肯定的。虽然变换了新的地方,融入了新的面孔,但至少我们还能在一起用羽毛球找到属于彼此的快乐,那也足够了。\r\n\r\n孩子的事情上,这一年约着她的同班同学打卡了不少地方,这也让集体一起遛娃成为了周末值得期待的活动之一。\r\n\r\n## 最后\r\n\r\n最后,2024 年就要搬进新的房子了,这是值得期待和努力的一件大事。希望自己和家人在新的环境中能收获新的惊喜,身体健康,和和美满。\r\n\r\n', 'bodyText': '本来没想着写年终总结 —— 主要是最近对于码字没太多的欲望,但翻到了 2021/2022 的一些年终记录,也看了不少其他网友博主 2023 年的总结,所以对自己说,还是写一写吧。\n2023 年对个人来说是变动的一年,这个变动主要体现在工作上。反观生活,除去家庭的一些琐事基本上也就是波澜不惊的一个状态。\n\n工作\n2023 年工作最大的变动之一就是公司搬迁新的厂区。随之而来是上下班通勤的变更,这一切让原本相对充裕的时间变得更加紧凑。但时间是最大的习惯,久而久之这就成了生活的一部分,朝九晚五体现的淋漓尽致。\n第二个变动最大的是新办公地点新办公规章。这一点影响很大,以至于让我不得不放弃了很多以前形成的一部分工具习惯,转身去重新接纳一些新的工具和平台。于是,有了现在的个人知识站点,有了飞书的使用体验,GitHub 更是一瞬间成为了个人最常逛和依赖的平台 —— 这也让我重新认识了这个平台的强大和无可替代。\n\n \n\n职业方向上探索了一把 AI,浅尝辄止又摸不着门道;mRNA 到 Protein 的优化道路上才刚刚看到入口,任重道远;只能背靠着老本行,在不断优化的道路上踉踉跄跄走着。\n职业生涯的道路上人来人往,铁打的营盘流水的兵,走了就走了,无需留念。\n生活\n生活上其实没什么太多说的,感觉到微妙变化的是比以前更加注意到自己和身边人的健康问题了。从老婆孩子,到母亲的腰椎问题,再到自己,再加上这一年的流感、肺炎(尤其是支原体肺炎),2023 年在健康这个问题上的确投入了很大的一部分时间和精力。\n家庭琐事上,家人彼此磕磕碰碰的事情总会有,生活无律,人生无常,我们更需要的是相互之间相互理解与包容。对于老婆和孩子,需要更多的关心和陪伴。\n运动这件事情上,基本还能保持着每周至少一场羽毛球,这是值得肯定的。虽然变换了新的地方,融入了新的面孔,但至少我们还能在一起用羽毛球找到属于彼此的快乐,那也足够了。\n孩子的事情上,这一年约着她的同班同学打卡了不少地方,这也让集体一起遛娃成为了周末值得期待的活动之一。\n最后\n最后,2024 年就要搬进新的房子了,这是值得期待和努力的一件大事。希望自己和家人在新的环境中能收获新的惊喜,身体健康,和和美满。', 'bodyHTML': '

本来没想着写年终总结 —— 主要是最近对于码字没太多的欲望,但翻到了 2021/2022 的一些年终记录,也看了不少其他网友博主 2023 年的总结,所以对自己说,还是写一写吧。

\n

2023 年对个人来说是变动的一年,这个变动主要体现在工作上。反观生活,除去家庭的一些琐事基本上也就是波澜不惊的一个状态。

\n\n

工作

\n

2023 年工作最大的变动之一就是公司搬迁新的厂区。随之而来是上下班通勤的变更,这一切让原本相对充裕的时间变得更加紧凑。但时间是最大的习惯,久而久之这就成了生活的一部分,朝九晚五体现的淋漓尽致。

\n

第二个变动最大的是新办公地点新办公规章。这一点影响很大,以至于让我不得不放弃了很多以前形成的一部分工具习惯,转身去重新接纳一些新的工具和平台。于是,有了现在的个人知识站点,有了飞书的使用体验,GitHub 更是一瞬间成为了个人最常逛和依赖的平台 —— 这也让我重新认识了这个平台的强大和无可替代。

\n

\n github-contributions-2023\n

\n

职业方向上探索了一把 AI,浅尝辄止又摸不着门道;mRNA 到 Protein 的优化道路上才刚刚看到入口,任重道远;只能背靠着老本行,在不断优化的道路上踉踉跄跄走着。

\n

职业生涯的道路上人来人往,铁打的营盘流水的兵,走了就走了,无需留念。

\n

生活

\n

生活上其实没什么太多说的,感觉到微妙变化的是比以前更加注意到自己和身边人的健康问题了。从老婆孩子,到母亲的腰椎问题,再到自己,再加上这一年的流感、肺炎(尤其是支原体肺炎),2023 年在健康这个问题上的确投入了很大的一部分时间和精力。

\n

家庭琐事上,家人彼此磕磕碰碰的事情总会有,生活无律,人生无常,我们更需要的是相互之间相互理解与包容。对于老婆和孩子,需要更多的关心和陪伴。

\n

运动这件事情上,基本还能保持着每周至少一场羽毛球,这是值得肯定的。虽然变换了新的地方,融入了新的面孔,但至少我们还能在一起用羽毛球找到属于彼此的快乐,那也足够了。

\n

孩子的事情上,这一年约着她的同班同学打卡了不少地方,这也让集体一起遛娃成为了周末值得期待的活动之一。

\n

最后

\n

最后,2024 年就要搬进新的房子了,这是值得期待和努力的一件大事。希望自己和家人在新的环境中能收获新的惊喜,身体健康,和和美满。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '苹果字体 PingFang SC 的一些踩坑记录', 'number': 49, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/49', 'createdAt': '2024-01-09T05:43:52Z', 'lastEditedAt': '2024-06-03T07:43:27Z', 'updatedAt': '2024-06-03T07:43:27Z', 'body': '曾经在 《[为 Windows 系统替换优雅的苹果字体](https://www.weiyan.cc/cookbook/%E5%BC%80%E5%8F%91%E8%BF%90%E7%BB%B4/windows/2021-02-19-win-font/)》中提到可在 Windows 中使用苹方字体替代默认的微软雅黑,这里就有一个问题即需要在 Wondows 下安装苹方字体 —— 如果你的字体安装错误,很有可能导致你的浏览器或其他应用出现乱码。\r\n\r\n## 浏览器乱码\r\n\r\n出现这个的原因主要是站点使用了 `PingFang SC` 的字体设置。\r\n```\r\nbody {\r\n font-family: PingFang SC,microsoft yahei,sans-serif;\r\n}\r\n```\r\n\r\n我们可以看到使用 F12 检查源码模式把 `font-family` 中的 `PingFang SC` 去掉后即可显示正常。\r\n\r\n## 字体安装后不起作用\r\n\r\n这里就涉及一个 **萍方** vs **苹方** vs **PingFang** 区别的一个问题。\r\n\r\n> 猛地看上去,萍方/苹方/PingFang 应该是同一个字体。但是,实际上的效果,却并不相同。那么,到底谁是真正的 pingfang sc呢? \r\n> \r\n> 这里以能否**以 PingFang SC 为名称识别出来,作为标准**。为什么这么说呢?因为网页里面的 font-family,写的都是 pingfang sc,也许萍方/苹方都是差不多的字体,但是不能在网页里面自动识别出来。所以,就等于零。\r\n> \r\n> ```\r\n> body {\r\n> font-family: PingFang SC,microsoft yahei,sans-serif;\r\n> }\r\n> ```\r\n> 比如,上述 css 定义,就来自于腾讯云主页。在实际的应用过程中,只有安装好的 pingfang sc 系列字体才能被识别【如下图中的右侧字体】。 \r\n> **注意:萍方/苹方,在安装的时候,文件名也都是 pingfang-sc 之类的文件名。但是,安装完成的真正成品,可不是这个拼音名字。进而导致字体不能识别。**\r\n> ![pingfang sc 区别](https://shub.weiyan.tech/kgarden/2024/01/fingfang-sc.png)\r\n> \r\n> From 《[由 pingfang sc 字体缺失,所暴露的字体加载顺序的潜规则](https://newsn.net/say/css-font-family-pingfang.html)》\r\n\r\n## 解决方案\r\n\r\n参考 《[由 pingfang sc 字体缺失,所暴露的字体加载顺序的潜规则](https://newsn.net/say/css-font-family-pingfang.html)》 一文的方案。\r\n\r\n### 安装 PingFang SC\r\n\r\n名称为 **PingFang SC** (英文) 的字体找了很久才在 GitHub 翻到一个(以防丢失,个人 Fork 了过来):[shenweiyan/PingFangSC-Fonts](https://github.com/shenweiyan/PingFangSC-Fonts),如有需要可以直接下载安装。\r\n\r\n> 国内大多数网页,在定义网页字体的时候,都是先定义 PingFang SC,然后定义微软雅黑。那么: \r\n> \r\n> - 正常来说,win 系统是不会安装 PingFang SC 字体的,所以,显示微软雅黑,页面正常。 \r\n> - 但是,一旦单独安装了 PingFang SC Light,页面就会识别出这个 Light 字体,页面不正常。 \r\n> - 解决方案是:再安装一个 PingFang SC Regular,页面会在 Light 之前优先识别 Regular,页面正常。 \r\n\r\n> \r\n> 如果您非要在 win 下面安装 pingfang sc 字体,可能要三思而后安装了。李鬼似乎有点多...\r\n\r\n> \r\n> ![PingFang SC Regular](https://shub.weiyan.tech/kgarden/2024/01/pingfang-sc-regular.png)\r\n\r\n### 删除 PingFang SC\r\n\r\n个人用的就是这一个方法,但是在 `C:\\Windows\\Fonts` 中删除的时候会提示 **该字体正在使用无法删除!所以,必须要关闭使用苹方字体的程序。**\r\n\r\n因此,我们需要:\r\n\r\n参考:《[电脑安装新字体,浏览器字体全变了,如何删除正在使用的苹方字体](https://www.bilibili.com/video/BV1nc411575s/)》 - 哔哩哔哩\r\n\r\n- 在 Windows 任务管理的进程中把浏览器相关的全部结束掉,如 360 浏览器相关的进程、Microsoft edge、Google Chrome 等等,全部选择结束任务。 \r\n- 把其他可能使用苹方字体的,如 OneNote、WPS、微信、... 这些的进程也全部结束掉。 \r\n\r\n最后,回到 `C:\\Windows\\Fonts` 中再次删除相应的苹方字体,发现即可成功删除。删除了这些苹方字体,浏览器上的字体显示也就恢复正常了。\r\n\r\n## 参考资料\r\n\r\n1. 苏南大叔,《[由 pingfang sc 字体缺失,所暴露的字体加载顺序的潜规则](https://newsn.net/say/css-font-family-pingfang.html)》\r\n2. 科技猎手2023,《[电脑安装新字体,浏览器字体全变了,如何删除正在使用的苹方字体](https://www.bilibili.com/video/BV1nc411575s/)》 - 哔哩哔哩', 'bodyText': '曾经在 《为 Windows 系统替换优雅的苹果字体》中提到可在 Windows 中使用苹方字体替代默认的微软雅黑,这里就有一个问题即需要在 Wondows 下安装苹方字体 —— 如果你的字体安装错误,很有可能导致你的浏览器或其他应用出现乱码。\n浏览器乱码\n出现这个的原因主要是站点使用了 PingFang SC 的字体设置。\nbody {\n font-family: PingFang SC,microsoft yahei,sans-serif;\n}\n\n我们可以看到使用 F12 检查源码模式把 font-family 中的 PingFang SC 去掉后即可显示正常。\n字体安装后不起作用\n这里就涉及一个 萍方 vs 苹方 vs PingFang 区别的一个问题。\n\n猛地看上去,萍方/苹方/PingFang 应该是同一个字体。但是,实际上的效果,却并不相同。那么,到底谁是真正的 pingfang sc呢?\n这里以能否以 PingFang SC 为名称识别出来,作为标准。为什么这么说呢?因为网页里面的 font-family,写的都是 pingfang sc,也许萍方/苹方都是差不多的字体,但是不能在网页里面自动识别出来。所以,就等于零。\nbody {\n font-family: PingFang SC,microsoft yahei,sans-serif;\n}\n\n比如,上述 css 定义,就来自于腾讯云主页。在实际的应用过程中,只有安装好的 pingfang sc 系列字体才能被识别【如下图中的右侧字体】。\n注意:萍方/苹方,在安装的时候,文件名也都是 pingfang-sc 之类的文件名。但是,安装完成的真正成品,可不是这个拼音名字。进而导致字体不能识别。\n\nFrom 《由 pingfang sc 字体缺失,所暴露的字体加载顺序的潜规则》\n\n解决方案\n参考 《由 pingfang sc 字体缺失,所暴露的字体加载顺序的潜规则》 一文的方案。\n安装 PingFang SC\n名称为 PingFang SC (英文) 的字体找了很久才在 GitHub 翻到一个(以防丢失,个人 Fork 了过来):shenweiyan/PingFangSC-Fonts,如有需要可以直接下载安装。\n\n国内大多数网页,在定义网页字体的时候,都是先定义 PingFang SC,然后定义微软雅黑。那么:\n\n正常来说,win 系统是不会安装 PingFang SC 字体的,所以,显示微软雅黑,页面正常。\n但是,一旦单独安装了 PingFang SC Light,页面就会识别出这个 Light 字体,页面不正常。\n解决方案是:再安装一个 PingFang SC Regular,页面会在 Light 之前优先识别 Regular,页面正常。\n\n\n\n如果您非要在 win 下面安装 pingfang sc 字体,可能要三思而后安装了。李鬼似乎有点多...\n\n\n\n\n删除 PingFang SC\n个人用的就是这一个方法,但是在 C:\\Windows\\Fonts 中删除的时候会提示 该字体正在使用无法删除!所以,必须要关闭使用苹方字体的程序。\n因此,我们需要:\n参考:《电脑安装新字体,浏览器字体全变了,如何删除正在使用的苹方字体》 - 哔哩哔哩\n\n在 Windows 任务管理的进程中把浏览器相关的全部结束掉,如 360 浏览器相关的进程、Microsoft edge、Google Chrome 等等,全部选择结束任务。\n把其他可能使用苹方字体的,如 OneNote、WPS、微信、... 这些的进程也全部结束掉。\n\n最后,回到 C:\\Windows\\Fonts 中再次删除相应的苹方字体,发现即可成功删除。删除了这些苹方字体,浏览器上的字体显示也就恢复正常了。\n参考资料\n\n苏南大叔,《由 pingfang sc 字体缺失,所暴露的字体加载顺序的潜规则》\n科技猎手2023,《电脑安装新字体,浏览器字体全变了,如何删除正在使用的苹方字体》 - 哔哩哔哩', 'bodyHTML': '

曾经在 《为 Windows 系统替换优雅的苹果字体》中提到可在 Windows 中使用苹方字体替代默认的微软雅黑,这里就有一个问题即需要在 Wondows 下安装苹方字体 —— 如果你的字体安装错误,很有可能导致你的浏览器或其他应用出现乱码。

\n

浏览器乱码

\n

出现这个的原因主要是站点使用了 PingFang SC 的字体设置。

\n
body {\n    font-family: PingFang SC,microsoft yahei,sans-serif;\n}\n
\n

我们可以看到使用 F12 检查源码模式把 font-family 中的 PingFang SC 去掉后即可显示正常。

\n

字体安装后不起作用

\n

这里就涉及一个 萍方 vs 苹方 vs PingFang 区别的一个问题。

\n
\n

猛地看上去,萍方/苹方/PingFang 应该是同一个字体。但是,实际上的效果,却并不相同。那么,到底谁是真正的 pingfang sc呢?

\n

这里以能否以 PingFang SC 为名称识别出来,作为标准。为什么这么说呢?因为网页里面的 font-family,写的都是 pingfang sc,也许萍方/苹方都是差不多的字体,但是不能在网页里面自动识别出来。所以,就等于零。

\n
body {\n   font-family: PingFang SC,microsoft yahei,sans-serif;\n}\n
\n

比如,上述 css 定义,就来自于腾讯云主页。在实际的应用过程中,只有安装好的 pingfang sc 系列字体才能被识别【如下图中的右侧字体】。
\n注意:萍方/苹方,在安装的时候,文件名也都是 pingfang-sc 之类的文件名。但是,安装完成的真正成品,可不是这个拼音名字。进而导致字体不能识别。
\npingfang sc 区别

\n

From 《由 pingfang sc 字体缺失,所暴露的字体加载顺序的潜规则

\n
\n

解决方案

\n

参考 《由 pingfang sc 字体缺失,所暴露的字体加载顺序的潜规则》 一文的方案。

\n

安装 PingFang SC

\n

名称为 PingFang SC (英文) 的字体找了很久才在 GitHub 翻到一个(以防丢失,个人 Fork 了过来):shenweiyan/PingFangSC-Fonts,如有需要可以直接下载安装。

\n
\n

国内大多数网页,在定义网页字体的时候,都是先定义 PingFang SC,然后定义微软雅黑。那么:

\n
    \n
  • 正常来说,win 系统是不会安装 PingFang SC 字体的,所以,显示微软雅黑,页面正常。
  • \n
  • 但是,一旦单独安装了 PingFang SC Light,页面就会识别出这个 Light 字体,页面不正常。
  • \n
  • 解决方案是:再安装一个 PingFang SC Regular,页面会在 Light 之前优先识别 Regular,页面正常。
  • \n
\n
\n
\n

如果您非要在 win 下面安装 pingfang sc 字体,可能要三思而后安装了。李鬼似乎有点多...

\n
\n
\n

PingFang SC Regular

\n
\n

删除 PingFang SC

\n

个人用的就是这一个方法,但是在 C:\\Windows\\Fonts 中删除的时候会提示 该字体正在使用无法删除!所以,必须要关闭使用苹方字体的程序。

\n

因此,我们需要:

\n

参考:《电脑安装新字体,浏览器字体全变了,如何删除正在使用的苹方字体》 - 哔哩哔哩

\n
    \n
  • 在 Windows 任务管理的进程中把浏览器相关的全部结束掉,如 360 浏览器相关的进程、Microsoft edge、Google Chrome 等等,全部选择结束任务。
  • \n
  • 把其他可能使用苹方字体的,如 OneNote、WPS、微信、... 这些的进程也全部结束掉。
  • \n
\n

最后,回到 C:\\Windows\\Fonts 中再次删除相应的苹方字体,发现即可成功删除。删除了这些苹方字体,浏览器上的字体显示也就恢复正常了。

\n

参考资料

\n
    \n
  1. 苏南大叔,《由 pingfang sc 字体缺失,所暴露的字体加载顺序的潜规则
  2. \n
  3. 科技猎手2023,《电脑安装新字体,浏览器字体全变了,如何删除正在使用的苹方字体》 - 哔哩哔哩
  4. \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '公众号'}, {'name': '1.3.10-Windows'}]}, 'comments': {'nodes': []}}, {'title': '2-框架依赖', 'number': 48, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/48', 'createdAt': '2024-01-08T03:49:03Z', 'lastEditedAt': '2024-01-12T07:11:22Z', 'updatedAt': '2024-04-24T06:54:28Z', 'body': '> 编译:[Shen Weiyan](https://www.weiyan.cc) \r\n> 原文: ', 'bodyText': '编译:Shen Weiyan\n原文:https://docs.galaxyproject.org/en/master/admin/python.html', 'bodyHTML': '
\n

编译:Shen Weiyan
\n原文:https://docs.galaxyproject.org/en/master/admin/python.html

\n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '3.1-Galaxy'}, 'labels': {'nodes': [{'name': '3.1.2-Administration'}]}, 'comments': {'nodes': []}}, {'title': '1-支持的 Python 版本', 'number': 47, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/47', 'createdAt': '2024-01-08T02:21:30Z', 'lastEditedAt': '2024-01-12T07:11:40Z', 'updatedAt': '2024-04-24T06:54:09Z', 'body': '> 编译:[沈维燕](https://www.weiyan.cc) \r\n> 原文: \r\n\r\nGalaxy 的核心功能目前支持 Python >=3.7。\r\n\r\n如果 Galaxy 排斥你正在使用的 Python 版本:\r\n\r\n1. 完全删除 Galaxy 使用的 Python virtualenv(可以使用 `GALAXY_VIRTUAL_ENV` 环境变量配置,默认为 `.venv` ),例如: `rm -rf /path/to/galaxy/.venv`。\r\n2. 如果您在 conda 环境中使用 Python(可以使用 `GALAXY_CONDA_ENV` 环境变量进行配置,默认为 `_galaxy_`),请将其删除,例如: `conda env remove -n _galaxy_`。\r\n3. 让 Galaxy 知道要使用哪个 Python 的方法有以下几种: \r\n - 如果您想从 conda 使用 Python,只需激活 `base` 环境,Galaxy 将为自己创建一个新的 conda 环境。\r\n - 否则: \r\n - 确保安装了受支持的 Python 版本。\r\n - 验证您要使用的 Python 解释器是否位于 `which -a python3 python` 输出中的第一个位置(如果您使用的是 Galaxy <=19.09,则为 `which -a python` )。如果不是这种情况: \r\n - 如果您使用的是 Galaxy >= 20.01,只需执行: `export GALAXY_PYTHON=/path/to/python`。\r\n - 如果你使用的是较旧版本的 Galaxy,你可以操控你的 shell 的 `PATH` 变量,将正确的版本置于首位。你可以通过创建一个新目录,将 python 的符号链接添加到其中,并将该目录置于 PATH 的最前面来完成此操作:\r\n ```bash\r\n % mkdir ~/galaxy-python\r\n % ln -s /path/to/python ~/galaxy-python/python\r\n % export PATH=~/galaxy-python:$PATH\r\n ```\r\n\r\n4. 从 Python 2 升级时,删除已编译的 `mako` 模板:\r\n ```basn\r\n % rm -rf /path/to/galaxy/database/compiled_templates/\r\n ```\r\n 这些模板将在启动 Galaxy 时自动重新生成。\r\n\r\n5. 再次启动 Galaxy。\r\n\r\n!!! abstract "注意"\r\n\r\n 如果您从源代码编译自己的 Python 解释器,请确保构建了 `ssl`、`sqlite3`、`curses` 和 `bz2` 模块,并且安装后可导入。这些 "额外" 模块是在编译过程的最后阶段构建的,并且是 Galaxy 框架所需的。如果在 Linux 上进行编译,您可能需要安装适用于 OpenSSL 和 Bzip2 的 `-dev` 包。您可能还需要使用共享库 (`--enable-shared`) 构建 Python。', 'bodyText': '编译:沈维燕\n原文:https://docs.galaxyproject.org/en/master/admin/python.html\n\nGalaxy 的核心功能目前支持 Python >=3.7。\n如果 Galaxy 排斥你正在使用的 Python 版本:\n\n\n完全删除 Galaxy 使用的 Python virtualenv(可以使用 GALAXY_VIRTUAL_ENV 环境变量配置,默认为 .venv ),例如: rm -rf /path/to/galaxy/.venv。\n\n\n如果您在 conda 环境中使用 Python(可以使用 GALAXY_CONDA_ENV 环境变量进行配置,默认为 _galaxy_),请将其删除,例如: conda env remove -n _galaxy_。\n\n\n让 Galaxy 知道要使用哪个 Python 的方法有以下几种:\n\n如果您想从 conda 使用 Python,只需激活 base 环境,Galaxy 将为自己创建一个新的 conda 环境。\n否则:\n\n确保安装了受支持的 Python 版本。\n验证您要使用的 Python 解释器是否位于 which -a python3 python 输出中的第一个位置(如果您使用的是 Galaxy <=19.09,则为 which -a python )。如果不是这种情况:\n\n如果您使用的是 Galaxy >= 20.01,只需执行: export GALAXY_PYTHON=/path/to/python。\n如果你使用的是较旧版本的 Galaxy,你可以操控你的 shell 的 PATH 变量,将正确的版本置于首位。你可以通过创建一个新目录,将 python 的符号链接添加到其中,并将该目录置于 PATH 的最前面来完成此操作:\n% mkdir ~/galaxy-python\n% ln -s /path/to/python ~/galaxy-python/python\n% export PATH=~/galaxy-python:$PATH\n\n\n\n\n\n\n\n\n从 Python 2 升级时,删除已编译的 mako 模板:\n% rm -rf /path/to/galaxy/database/compiled_templates/\n\n这些模板将在启动 Galaxy 时自动重新生成。\n\n\n再次启动 Galaxy。\n\n\n!!! abstract "注意"\n如果您从源代码编译自己的 Python 解释器,请确保构建了 `ssl`、`sqlite3`、`curses` 和 `bz2` 模块,并且安装后可导入。这些 "额外" 模块是在编译过程的最后阶段构建的,并且是 Galaxy 框架所需的。如果在 Linux 上进行编译,您可能需要安装适用于 OpenSSL 和 Bzip2 的 `-dev` 包。您可能还需要使用共享库 (`--enable-shared`) 构建 Python。', 'bodyHTML': '
\n

编译:沈维燕
\n原文:https://docs.galaxyproject.org/en/master/admin/python.html

\n
\n

Galaxy 的核心功能目前支持 Python >=3.7。

\n

如果 Galaxy 排斥你正在使用的 Python 版本:

\n
    \n
  1. \n

    完全删除 Galaxy 使用的 Python virtualenv(可以使用 GALAXY_VIRTUAL_ENV 环境变量配置,默认为 .venv ),例如: rm -rf /path/to/galaxy/.venv

    \n
  2. \n
  3. \n

    如果您在 conda 环境中使用 Python(可以使用 GALAXY_CONDA_ENV 环境变量进行配置,默认为 _galaxy_),请将其删除,例如: conda env remove -n _galaxy_

    \n
  4. \n
  5. \n

    让 Galaxy 知道要使用哪个 Python 的方法有以下几种:

    \n
      \n
    • 如果您想从 conda 使用 Python,只需激活 base 环境,Galaxy 将为自己创建一个新的 conda 环境。
    • \n
    • 否则:\n
        \n
      • 确保安装了受支持的 Python 版本。
      • \n
      • 验证您要使用的 Python 解释器是否位于 which -a python3 python 输出中的第一个位置(如果您使用的是 Galaxy <=19.09,则为 which -a python )。如果不是这种情况:\n
          \n
        • 如果您使用的是 Galaxy >= 20.01,只需执行: export GALAXY_PYTHON=/path/to/python
        • \n
        • 如果你使用的是较旧版本的 Galaxy,你可以操控你的 shell 的 PATH 变量,将正确的版本置于首位。你可以通过创建一个新目录,将 python 的符号链接添加到其中,并将该目录置于 PATH 的最前面来完成此操作:\n
          % mkdir ~/galaxy-python\n% ln -s /path/to/python ~/galaxy-python/python\n% export PATH=~/galaxy-python:$PATH
          \n
        • \n
        \n
      • \n
      \n
    • \n
    \n
  6. \n
  7. \n

    从 Python 2 升级时,删除已编译的 mako 模板:

    \n
    % rm -rf /path/to/galaxy/database/compiled_templates/\n
    \n

    这些模板将在启动 Galaxy 时自动重新生成。

    \n
  8. \n
  9. \n

    再次启动 Galaxy。

    \n
  10. \n
\n

!!! abstract "注意"

\n
如果您从源代码编译自己的 Python 解释器,请确保构建了 `ssl`、`sqlite3`、`curses` 和 `bz2` 模块,并且安装后可导入。这些 "额外" 模块是在编译过程的最后阶段构建的,并且是 Galaxy 框架所需的。如果在 Linux 上进行编译,您可能需要安装适用于 OpenSSL 和 Bzip2 的 `-dev` 包。您可能还需要使用共享库 (`--enable-shared`) 构建 Python。\n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '3.1-Galaxy'}, 'labels': {'nodes': [{'name': '3.1.2-Administration'}]}, 'comments': {'nodes': []}}, {'title': 'Galaxy Project 的 Sphinx 文档部署', 'number': 46, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/46', 'createdAt': '2024-01-05T07:29:59Z', 'lastEditedAt': '2024-02-02T01:23:29Z', 'updatedAt': '2024-04-24T06:29:53Z', 'body': ' 是 Galaxy Project 官方的文档地址链接,这是一个基于 [Sphinx](https://www.sphinx-doc.org/) + [Read the Docs](https://readthedocs.org/) 的文档站点。如果我们也想要创建一个这样一模一样的 Galaxy 文档需要怎么操作呢?\r\n\r\n\r\n\r\n虽然 [Galaxy 官方文档](https://docs.galaxyproject.org/en/master/#building-this-documentation) 也给出了关于构建该文档的一些说明,但没有太多细节。\r\n\r\n> If you have your own copy of the Galaxy source code, you can also generate your own version of this documentation. Run the following command from the Galaxy’s root:\r\n> ```\r\n> $ make docs\r\n> ```\r\n> The generated documentation will be in `doc/build/html/` and can be viewed with a web browser. Note that you will need to install Sphinx and other module dependencies which are listed in the Makefile in the Galaxy root folder.\r\n\r\n下面我们来详细分解一下 `make docs` 这个命令具体执行的构建步骤。\r\n\r\n首先,在 Galaxy 根目录的执行 `make docs`,主要是执行了该目录下 [Makefile](https://github.com/galaxyproject/galaxy/blob/dev/Makefile) 中的这几句命令:\r\n```\r\ndocs: ## Generate HTML documentation.\r\n# Run following commands to setup the Python portion of the requirements:\r\n# $ ./scripts/common_startup.sh\r\n# $ . .venv/bin/activate\r\n# $ pip install -r requirements.txt -r lib/galaxy/dependencies/dev-requirements.txt\r\n\t$(IN_VENV) $(MAKE) -C doc clean\r\n\t$(IN_VENV) $(MAKE) -C doc html\r\n```\r\n- `$(MAKE)`就是预设的 `make` 这个命令的名称(或者路径)。 \r\n- `-C`:到指定目录下读取 Makefile 文件并执行(给出指定的目录的路径)。 \r\n\r\n第二步,读取 `doc` 目录下的 [Makefile](https://github.com/galaxyproject/galaxy/blob/dev/doc/Makefile) 文件,并执行 `make html`。\r\n```\r\nhtml: $(GENERATED_RST)\r\n\t$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html\r\n\t@echo\r\n\t@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."\r\n```\r\n\r\n结合其中的一些参数,其实最终就是执行了下面这个命令完成最终的构建。\r\n```bash\r\nsphinx-build -b html -d build/doctrees source build/html\r\n```\r\n\r\n- sphinx-build [OPTIONS] SOURCEDIR OUTPUTDIR [FILENAMES...]\r\n- sourcedir:path to documentation source files\r\n- outputdir:path to output directory\r\n- `-b`:BUILDER,builder to use (default: html)\r\n\r\n了解了以上几个步骤后,我们就可以把 Galaxy 根目录的 doc 目录单独拎出来,通过 Sphinx 的命令实现独立构建部署。\r\n\r\n## 1. 安装必须依赖\r\n\r\n主要包括三个依赖。\r\n```\r\npip3 install Sphinx sphinx_rtd_theme myst_parser\r\n```\r\n\r\n## 2. 修改配置\r\n\r\n由于 `sphinx-build` 会读取 `source/conf.py` 并执行,但这个文件调用了 [`galaxy.version`](https://github.com/galaxyproject/galaxy/blob/dev/lib/galaxy/version.py) 模块:\r\n![No module named \'galaxy\'](https://shub.weiyan.tech/kgarden/2024/01/no-galaxy-version.png)\r\n\r\n所以,如果我们想要把 `galaxy/doc` 和 Galaxy 独立开来进行部署,就需要修改一下 `source/conf.py`:\r\n```python\r\n# The short X.Y version.\r\n#from galaxy.version import (\r\n# VERSION,\r\n# VERSION_MAJOR,\r\n#)\r\n\r\nVERSION_MAJOR = "23.1"\r\nVERSION_MINOR = "5.dev0"\r\nVERSION = VERSION_MAJOR + (f".{VERSION_MINOR}" if VERSION_MINOR else "")\r\n```\r\n\r\n## 3. 执行构建\r\n```bash\r\n$ sphinx-build -b html -d build/doctrees source build/html\r\nRunning Sphinx v7.2.6\r\nmaking output directory... done\r\nmyst v2.0.0: MdParserConfig(commonmark_only=False, gfm_only=False, enable_extensions={\'deflist\', \'attrs_block\', \'substitution\'}, disable_syntax=[], all_links_external=False, url_schemes=(\'http\', \'https\', \'mailto\', \'ftp\'), ref_domains=None, fence_as_directive=set(), number_code_blocks=[], title_to_header=False, heading_anchors=5, heading_slug_func=, html_meta={}, footnote_transition=True, words_per_minute=200, substitutions={}, linkify_fuzzy_links=True, dmath_allow_labels=True, dmath_allow_space=True, dmath_allow_digits=True, dmath_double_inline=False, update_mathjax=True, mathjax_classes=\'tex2jax_process|mathjax_process|math|output_area\', enable_checkboxes=False, suppress_warnings=[], highlight_code_blocks=True)\r\nloading intersphinx inventory from https://docs.python.org/3/objects.inv...\r\nloading intersphinx inventory from https://requests.readthedocs.io/en/master/objects.inv...\r\nintersphinx inventory has moved: https://requests.readthedocs.io/en/master/objects.inv -> https://requests.readthedocs.io/en/latest/objects.inv\r\nbuilding [mo]: targets for 0 po files that are out of date\r\nwriting output... \r\nbuilding [html]: targets for 332 source files that are out of date\r\nupdating environment: [new config] 332 added, 0 changed, 0 removed\r\nreading sources... [100%] ts_api_doc\r\n\r\n...\r\n\r\ngenerating indices... genindex done\r\nhighlighting module code... \r\nwriting additional pages... search done\r\ncopying images... [100%] releases/images/23.1-hdf5.png\r\ndumping search index in English (code: en)... done\r\ndumping object inventory... done\r\nbuild succeeded, 1223 warnings.\r\n\r\nThe HTML pages are in build/html.\r\n```\r\n\r\n最后生成的静态文件都保存在了 `build/html` 目录,我们可以借助 NGINX 或者其他 Pages 就可以直接看到一个一模一样对应当前 Repo 版本的 Galaxy Project 文档了。', 'bodyText': 'https://docs.galaxyproject.org/ 是 Galaxy Project 官方的文档地址链接,这是一个基于 Sphinx + Read the Docs 的文档站点。如果我们也想要创建一个这样一模一样的 Galaxy 文档需要怎么操作呢?\n\n虽然 Galaxy 官方文档 也给出了关于构建该文档的一些说明,但没有太多细节。\n\nIf you have your own copy of the Galaxy source code, you can also generate your own version of this documentation. Run the following command from the Galaxy’s root:\n$ make docs\n\nThe generated documentation will be in doc/build/html/ and can be viewed with a web browser. Note that you will need to install Sphinx and other module dependencies which are listed in the Makefile in the Galaxy root folder.\n\n下面我们来详细分解一下 make docs 这个命令具体执行的构建步骤。\n首先,在 Galaxy 根目录的执行 make docs,主要是执行了该目录下 Makefile 中的这几句命令:\ndocs: ## Generate HTML documentation.\n# Run following commands to setup the Python portion of the requirements:\n# $ ./scripts/common_startup.sh\n# $ . .venv/bin/activate\n# $ pip install -r requirements.txt -r lib/galaxy/dependencies/dev-requirements.txt\n\t$(IN_VENV) $(MAKE) -C doc clean\n\t$(IN_VENV) $(MAKE) -C doc html\n\n\n$(MAKE)就是预设的 make 这个命令的名称(或者路径)。\n-C:到指定目录下读取 Makefile 文件并执行(给出指定的目录的路径)。\n\n第二步,读取 doc 目录下的 Makefile 文件,并执行 make html。\nhtml: $(GENERATED_RST)\n\t$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html\n\t@echo\n\t@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."\n\n结合其中的一些参数,其实最终就是执行了下面这个命令完成最终的构建。\nsphinx-build -b html -d build/doctrees source build/html\n\nsphinx-build [OPTIONS] SOURCEDIR OUTPUTDIR [FILENAMES...]\nsourcedir:path to documentation source files\noutputdir:path to output directory\n-b:BUILDER,builder to use (default: html)\n\n了解了以上几个步骤后,我们就可以把 Galaxy 根目录的 doc 目录单独拎出来,通过 Sphinx 的命令实现独立构建部署。\n1. 安装必须依赖\n主要包括三个依赖。\npip3 install Sphinx sphinx_rtd_theme myst_parser\n\n2. 修改配置\n由于 sphinx-build 会读取 source/conf.py 并执行,但这个文件调用了 galaxy.version 模块:\n\n所以,如果我们想要把 galaxy/doc 和 Galaxy 独立开来进行部署,就需要修改一下 source/conf.py:\n# The short X.Y version.\n#from galaxy.version import (\n# VERSION,\n# VERSION_MAJOR,\n#)\n\nVERSION_MAJOR = "23.1"\nVERSION_MINOR = "5.dev0"\nVERSION = VERSION_MAJOR + (f".{VERSION_MINOR}" if VERSION_MINOR else "")\n3. 执行构建\n$ sphinx-build -b html -d build/doctrees source build/html\nRunning Sphinx v7.2.6\nmaking output directory... done\nmyst v2.0.0: MdParserConfig(commonmark_only=False, gfm_only=False, enable_extensions={\'deflist\', \'attrs_block\', \'substitution\'}, disable_syntax=[], all_links_external=False, url_schemes=(\'http\', \'https\', \'mailto\', \'ftp\'), ref_domains=None, fence_as_directive=set(), number_code_blocks=[], title_to_header=False, heading_anchors=5, heading_slug_func=, html_meta={}, footnote_transition=True, words_per_minute=200, substitutions={}, linkify_fuzzy_links=True, dmath_allow_labels=True, dmath_allow_space=True, dmath_allow_digits=True, dmath_double_inline=False, update_mathjax=True, mathjax_classes=\'tex2jax_process|mathjax_process|math|output_area\', enable_checkboxes=False, suppress_warnings=[], highlight_code_blocks=True)\nloading intersphinx inventory from https://docs.python.org/3/objects.inv...\nloading intersphinx inventory from https://requests.readthedocs.io/en/master/objects.inv...\nintersphinx inventory has moved: https://requests.readthedocs.io/en/master/objects.inv -> https://requests.readthedocs.io/en/latest/objects.inv\nbuilding [mo]: targets for 0 po files that are out of date\nwriting output... \nbuilding [html]: targets for 332 source files that are out of date\nupdating environment: [new config] 332 added, 0 changed, 0 removed\nreading sources... [100%] ts_api_doc\n\n...\n\ngenerating indices... genindex done\nhighlighting module code... \nwriting additional pages... search done\ncopying images... [100%] releases/images/23.1-hdf5.png\ndumping search index in English (code: en)... done\ndumping object inventory... done\nbuild succeeded, 1223 warnings.\n\nThe HTML pages are in build/html.\n最后生成的静态文件都保存在了 build/html 目录,我们可以借助 NGINX 或者其他 Pages 就可以直接看到一个一模一样对应当前 Repo 版本的 Galaxy Project 文档了。', 'bodyHTML': '

https://docs.galaxyproject.org/ 是 Galaxy Project 官方的文档地址链接,这是一个基于 Sphinx + Read the Docs 的文档站点。如果我们也想要创建一个这样一模一样的 Galaxy 文档需要怎么操作呢?

\n\n

虽然 Galaxy 官方文档 也给出了关于构建该文档的一些说明,但没有太多细节。

\n
\n

If you have your own copy of the Galaxy source code, you can also generate your own version of this documentation. Run the following command from the Galaxy’s root:

\n
$ make docs\n
\n

The generated documentation will be in doc/build/html/ and can be viewed with a web browser. Note that you will need to install Sphinx and other module dependencies which are listed in the Makefile in the Galaxy root folder.

\n
\n

下面我们来详细分解一下 make docs 这个命令具体执行的构建步骤。

\n

首先,在 Galaxy 根目录的执行 make docs,主要是执行了该目录下 Makefile 中的这几句命令:

\n
docs: ## Generate HTML documentation.\n# Run following commands to setup the Python portion of the requirements:\n#   $ ./scripts/common_startup.sh\n#   $ . .venv/bin/activate\n#   $ pip install -r requirements.txt -r lib/galaxy/dependencies/dev-requirements.txt\n\t$(IN_VENV) $(MAKE) -C doc clean\n\t$(IN_VENV) $(MAKE) -C doc html\n
\n
    \n
  • $(MAKE)就是预设的 make 这个命令的名称(或者路径)。
  • \n
  • -C:到指定目录下读取 Makefile 文件并执行(给出指定的目录的路径)。
  • \n
\n

第二步,读取 doc 目录下的 Makefile 文件,并执行 make html

\n
html: $(GENERATED_RST)\n\t$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html\n\t@echo\n\t@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."\n
\n

结合其中的一些参数,其实最终就是执行了下面这个命令完成最终的构建。

\n
sphinx-build -b html -d build/doctrees source build/html
\n
    \n
  • sphinx-build [OPTIONS] SOURCEDIR OUTPUTDIR [FILENAMES...]
  • \n
  • sourcedir:path to documentation source files
  • \n
  • outputdir:path to output directory
  • \n
  • -b:BUILDER,builder to use (default: html)
  • \n
\n

了解了以上几个步骤后,我们就可以把 Galaxy 根目录的 doc 目录单独拎出来,通过 Sphinx 的命令实现独立构建部署。

\n

1. 安装必须依赖

\n

主要包括三个依赖。

\n
pip3 install Sphinx sphinx_rtd_theme myst_parser\n
\n

2. 修改配置

\n

由于 sphinx-build 会读取 source/conf.py 并执行,但这个文件调用了 galaxy.version 模块:
\nNo module named \'galaxy\'

\n

所以,如果我们想要把 galaxy/doc 和 Galaxy 独立开来进行部署,就需要修改一下 source/conf.py

\n
# The short X.Y version.\n#from galaxy.version import (\n#    VERSION,\n#    VERSION_MAJOR,\n#)\n\nVERSION_MAJOR = "23.1"\nVERSION_MINOR = "5.dev0"\nVERSION = VERSION_MAJOR + (f".{VERSION_MINOR}" if VERSION_MINOR else "")
\n

3. 执行构建

\n
$ sphinx-build -b html -d build/doctrees   source build/html\nRunning Sphinx v7.2.6\nmaking output directory... done\nmyst v2.0.0: MdParserConfig(commonmark_only=False, gfm_only=False, enable_extensions={\'deflist\', \'attrs_block\', \'substitution\'}, disable_syntax=[], all_links_external=False, url_schemes=(\'http\', \'https\', \'mailto\', \'ftp\'), ref_domains=None, fence_as_directive=set(), number_code_blocks=[], title_to_header=False, heading_anchors=5, heading_slug_func=<function make_id at 0x7f46201a6a60>, html_meta={}, footnote_transition=True, words_per_minute=200, substitutions={}, linkify_fuzzy_links=True, dmath_allow_labels=True, dmath_allow_space=True, dmath_allow_digits=True, dmath_double_inline=False, update_mathjax=True, mathjax_classes=\'tex2jax_process|mathjax_process|math|output_area\', enable_checkboxes=False, suppress_warnings=[], highlight_code_blocks=True)\nloading intersphinx inventory from https://docs.python.org/3/objects.inv...\nloading intersphinx inventory from https://requests.readthedocs.io/en/master/objects.inv...\nintersphinx inventory has moved: https://requests.readthedocs.io/en/master/objects.inv -> https://requests.readthedocs.io/en/latest/objects.inv\nbuilding [mo]: targets for 0 po files that are out of date\nwriting output... \nbuilding [html]: targets for 332 source files that are out of date\nupdating environment: [new config] 332 added, 0 changed, 0 removed\nreading sources... [100%] ts_api_doc\n\n...\n\ngenerating indices... genindex done\nhighlighting module code... \nwriting additional pages... search done\ncopying images... [100%] releases/images/23.1-hdf5.png\ndumping search index in English (code: en)... done\ndumping object inventory... done\nbuild succeeded, 1223 warnings.\n\nThe HTML pages are in build/html.
\n

最后生成的静态文件都保存在了 build/html 目录,我们可以借助 NGINX 或者其他 Pages 就可以直接看到一个一模一样对应当前 Repo 版本的 Galaxy Project 文档了。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '3.1-Galaxy'}, 'labels': {'nodes': [{'name': '公众号'}, {'name': '3.1.x-GalaxyOther'}]}, 'comments': {'nodes': []}}, {'title': '更新记录', 'number': 45, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/45', 'createdAt': '2024-01-04T05:50:47Z', 'lastEditedAt': '2024-07-16T05:55:41Z', 'updatedAt': '2024-07-16T05:55:43Z', 'body': '记录一下本知识仓库 [Knowledge-Garden](https://github.com/shenweiyan/Knowledge-Garden) 的一些主要更新记录。\r\n\r\n\r\n\r\n#### 2024-07-16\r\n- GitHub Pages 域名由 [doc.weiyan.cc](https://doc.weiyan.cc/) 变更为 [gh-pages.weiyan.cc](https://gh-pages.weiyan.cc/)。\r\n\r\n#### 2024-01-04 \r\n- 域名 `weiyan.cc` DNS 从 Cloudflare 转回阿里云。 \r\n- 把站点从 [Cloudflare Pages](https://pages.cloudflare.com/) 转移到 [Netlify](https://app.netlify.com/),绑定 [www.weiyan.cc](https://www.weiyan.cc/),实现 [weiyan.cc](https://weiyan.cc/) 重定向到 www 主域名 (Redirects automatically to primary domain)。\r\n\r\n#### 2023-11-28 \r\n- 镜像站点([weiyan.pages.dev](https://weiyan.pages.dev/))部署到 [Cloudflare Pages](https://pages.cloudflare.com/),绑定自定义域名 [weiyan.cc](https://weiyan.cc/)。 \r\n\r\n#### 2023-10-16 \r\n- GitHub 正式创建 [Knowledge-Garden](https://github.com/shenweiyan/Knowledge-Garden) 仓库,开启 GitHub Pages,绑定 [doc.weiyan.cc](https://doc.weiyan.cc/)。', 'bodyText': '记录一下本知识仓库 Knowledge-Garden 的一些主要更新记录。\n\n2024-07-16\n\nGitHub Pages 域名由 doc.weiyan.cc 变更为 gh-pages.weiyan.cc。\n\n2024-01-04\n\n域名 weiyan.cc DNS 从 Cloudflare 转回阿里云。\n把站点从 Cloudflare Pages 转移到 Netlify,绑定 www.weiyan.cc,实现 weiyan.cc 重定向到 www 主域名 (Redirects automatically to primary domain)。\n\n2023-11-28\n\n镜像站点(weiyan.pages.dev)部署到 Cloudflare Pages,绑定自定义域名 weiyan.cc。\n\n2023-10-16\n\nGitHub 正式创建 Knowledge-Garden 仓库,开启 GitHub Pages,绑定 doc.weiyan.cc。', 'bodyHTML': '

记录一下本知识仓库 Knowledge-Garden 的一些主要更新记录。

\n\n

2024-07-16

\n\n

2024-01-04

\n\n

2023-11-28

\n\n

2023-10-16

\n', 'author': {'login': 'shenweiyan'}, 'category': {'name': '0.1-站点'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '不要使用 requirements.txt', 'number': 44, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/44', 'createdAt': '2024-01-03T07:50:27Z', 'lastEditedAt': '2024-01-03T07:55:06Z', 'updatedAt': '2024-01-03T07:55:06Z', 'body': '> 作者:[Miikka Koskinen](https://miikka.me/) \r\n> 编译:[沈维燕](https://weiyan.cc) \r\n> 时间:原文发表于 2023-10-31 \r\n> 原文:[Do not use requirements.txt](https://quanttype.net/posts/2023-10-31-do-not-use-requirements.txt.html)\r\n\r\n你是否在用 Python 开发后端服务?我有两条建议:\r\n\r\n- 不要使用 `pip` 和 `requirements.txt` 来管理 Python 依赖。它们缺乏一些应该内置的关键功能。\r\n- 改用 [Poetry](https://python-poetry.org/)。\r\n\r\n\r\n\r\n对我来说,第一条建议毋庸置疑。第二条则更具有暂时性:Poetry 是一个很好的选择,但并非唯一值得考虑的选择。\r\n\r\n我将在下面进行解释。\r\n\r\n请注意:如果你使用 Python 做其他事情而不是构建后端服务,那么本文中的建议可能并不适用于你。例如,如果你是[一个正在迁移 `setup.py` 的库开发者](https://gregoryszorc.com/blog/2023/10/30/my-user-experience-porting-off-setup.py/),Poetry 并不明显是一个完美的选择。\r\n\r\n## PIP 缺失的功能\r\n[pip](https://pypi.org/project/pip/) 是一个工具,你可以用它从 [The Python Package Index (PyPI)](https://pypi.org/) 中安装软件包。它随 Python 一起安装,如果你是 Python 开发者,你可能已经多次使用过它。\r\n\r\n管理 Python 项目依赖的传统方式是将它们列在一个名为 `requirements.txt` 的文件中,并使用 `pip install -r requirements.txt` 进行安装。然而,`pip` 被设计成一个软件包安装工具,而不是一个功能齐全的项目工作流工具。**pip 缺乏两个关键功能,即依赖的锁定文件 (dependency lockfiles) 和虚拟环境的自动管理(automatic management of virtualenvs)。**\r\n\r\n## 依赖锁定文件\r\n如果你希望在所有环境中(比如你的笔记本电脑、持续集成(CI)、生产环境)获得相同的行为,你需要锁定你的依赖项及其传递依赖的版本。你可以在 `requirements.txt` 中锁定你直接依赖的版本,例如,使用 `requests==2.31.0` 而不是 `requests`。\r\n\r\n然而,pip 不会锁定传递依赖的版本。这可以通过使用 [pip-tools](https://github.com/jazzband/pip-tools) 来解决,将 `requirements.txt` 扩展成一个列出完整依赖图的文件,包括准确版本和构件的校验和(checksums for the artifacts)。pip-tools 很不错,但你需要自行设置并弄清楚它如何适应你的工作流程。\r\n\r\n在其他编程语言中,这个功能是基本要求的 - 例如,npm 多年来一直有 `package-lock.json`,Cargo 也有 `Cargo.lock`。这个功能实在应该是一个项目工作流工具中的内置功能。\r\n\r\n## 虚拟环境的自动管理\r\n\r\n在 Python 中创建隔离环境的方式是使用 [virtualenvs](https://docs.python.org/3/library/venv.html)。传统上,你需要手动管理它们:通过一个 shell 命令创建一个(比如 `python -m venv example` 来创建名为 `example` 的虚拟环境),当你想要使用它时,需要用另一个 shell 命令来激活它。\r\n\r\n这容易出错:忘记激活虚拟环境或者激活错误的虚拟环境是常见的错误。有一堆的解决方法。例如,你可以使用 [pyenv-virtualenv](https://github.com/pyenv/pyenv-virtualenv),在进入项目目录时让你的 shell 自动激活一个虚拟环境。[direnv](https://github.com/direnv/direnv/wiki/Python) 也可以做到。\r\n\r\n同样,这也应该成为工作流工具中的一个内置功能。你不应该需要将多个工具粘合在一起。你不会听到 npm 或 Cargo 用户在虚拟环境上遇到问题的。\r\n\r\n## Poetry 及其他选择\r\n\r\n幸运的是,许多人已经意识到这些问题并努力解决它们。不太幸运的是,这导致了大量的 Python 项目工作流工具涌现。那么该如何选择呢?\r\n\r\n我的建议是:**选择 [Poetry](https://python-poetry.org/docs/)**。它有锁定文件,有虚拟环境管理,而且很受欢迎且在积极开发中。根据我的经验,它并不完美,但是它起作用。\r\n\r\n你也可以考虑 [Hatch](https://hatch.pypa.io/latest/) 或 [PDM](https://github.com/pdm-project/pdm)。它们与 Poetry 相似。我自己没有使用过它们,但我听说其他人成功地使用了它们。Hatch 似乎在库作者 (library authors) 中特别受欢迎。\r\n\r\n如果你正在寻找一个更强大的选项,可以处理多个子项目,[Pants 构建系统](https://www.pantsbuild.org/)在 Python 支持方面做得很好。然而,它的学习曲线相对陡峭。\r\n\r\n最后,如果你正在寻找一个类似 rustup 那样可以为你安装 Python 的解决方案,那么有 [rye](https://github.com/mitsuhiko/rye)。它是新的实验性工具,但也许它对你来说是正确的选择?\r\n\r\n## 哪个是权威的工作流工具?\r\n\r\n如果 Python 自带一个权威的项目工作流工具会很好。很多人希望 pip 成为这样一个工具。Node.js 自带 npm,Rust 自带 Cargo,那么为什么 Python 就不能有一个呢?为什么会有这么多竞争的选择呢?\r\n\r\n据我所知,最大的障碍是,由于 Python 被广泛使用且用于许多不同的用例,制定一个通用的官方解决方案是困难且缓慢的(并且资金不足的)工作。另外,也不清楚 pip 是否适合这些功能。\r\n\r\n如果你想了解更多信息,请阅读和听取这些与我不同、深度参与 Python 社区的人的意见: \r\n- Stargirl (Thea Flowers) on Fediverse:《[所以你想解决 Python 打包问题:一个实用指南](https://hachyderm.io/@stargirl/109697057391904145)》\r\n- Pradyun Gedam:《[关于 Python 打包生态系统的思考](https://pradyunsg.me/blog/2023/01/21/thoughts-on-python-packaging/)》\r\n- Talk Python to Me (podcast):《[重新构想 Python 的打包工作流程](https://talkpython.fm/episodes/show/406/reimagining-pythons-packaging-workflows)》\r\n\r\n## 关于 Clojure \r\n\r\n阅读我的博客的 Clojure 开发者可能会问:嘿,Clojure 怎么样?为什么我们没有锁定文件呢?这是一个很好的问题!\r\n\r\nClojure 社区通过始终使用明确的版本而不是版本范围来解决了这个问题,即使在库中也是如此。版本描述实际上支持范围,但没有人会使用它们。这样,只要版本解析算法稳定,你总是会得到相同的版本。\r\n\r\n理论上,传递依赖项版本不匹配可能是一个问题,但 Clojure 支持一种编码风格,很少引起问题。\r\n\r\n相比之下,在 Python 和 Node.js 社区,通常期望库列出其依赖项的版本范围,而软件包管理工具会抱怨版本不匹配的问题。', 'bodyText': '作者:Miikka Koskinen\n编译:沈维燕\n时间:原文发表于 2023-10-31\n原文:Do not use requirements.txt\n\n你是否在用 Python 开发后端服务?我有两条建议:\n\n不要使用 pip 和 requirements.txt 来管理 Python 依赖。它们缺乏一些应该内置的关键功能。\n改用 Poetry。\n\n\n对我来说,第一条建议毋庸置疑。第二条则更具有暂时性:Poetry 是一个很好的选择,但并非唯一值得考虑的选择。\n我将在下面进行解释。\n请注意:如果你使用 Python 做其他事情而不是构建后端服务,那么本文中的建议可能并不适用于你。例如,如果你是一个正在迁移 setup.py 的库开发者,Poetry 并不明显是一个完美的选择。\nPIP 缺失的功能\npip 是一个工具,你可以用它从 The Python Package Index (PyPI) 中安装软件包。它随 Python 一起安装,如果你是 Python 开发者,你可能已经多次使用过它。\n管理 Python 项目依赖的传统方式是将它们列在一个名为 requirements.txt 的文件中,并使用 pip install -r requirements.txt 进行安装。然而,pip 被设计成一个软件包安装工具,而不是一个功能齐全的项目工作流工具。pip 缺乏两个关键功能,即依赖的锁定文件 (dependency lockfiles) 和虚拟环境的自动管理(automatic management of virtualenvs)。\n依赖锁定文件\n如果你希望在所有环境中(比如你的笔记本电脑、持续集成(CI)、生产环境)获得相同的行为,你需要锁定你的依赖项及其传递依赖的版本。你可以在 requirements.txt 中锁定你直接依赖的版本,例如,使用 requests==2.31.0 而不是 requests。\n然而,pip 不会锁定传递依赖的版本。这可以通过使用 pip-tools 来解决,将 requirements.txt 扩展成一个列出完整依赖图的文件,包括准确版本和构件的校验和(checksums for the artifacts)。pip-tools 很不错,但你需要自行设置并弄清楚它如何适应你的工作流程。\n在其他编程语言中,这个功能是基本要求的 - 例如,npm 多年来一直有 package-lock.json,Cargo 也有 Cargo.lock。这个功能实在应该是一个项目工作流工具中的内置功能。\n虚拟环境的自动管理\n在 Python 中创建隔离环境的方式是使用 virtualenvs。传统上,你需要手动管理它们:通过一个 shell 命令创建一个(比如 python -m venv example 来创建名为 example 的虚拟环境),当你想要使用它时,需要用另一个 shell 命令来激活它。\n这容易出错:忘记激活虚拟环境或者激活错误的虚拟环境是常见的错误。有一堆的解决方法。例如,你可以使用 pyenv-virtualenv,在进入项目目录时让你的 shell 自动激活一个虚拟环境。direnv 也可以做到。\n同样,这也应该成为工作流工具中的一个内置功能。你不应该需要将多个工具粘合在一起。你不会听到 npm 或 Cargo 用户在虚拟环境上遇到问题的。\nPoetry 及其他选择\n幸运的是,许多人已经意识到这些问题并努力解决它们。不太幸运的是,这导致了大量的 Python 项目工作流工具涌现。那么该如何选择呢?\n我的建议是:选择 Poetry。它有锁定文件,有虚拟环境管理,而且很受欢迎且在积极开发中。根据我的经验,它并不完美,但是它起作用。\n你也可以考虑 Hatch 或 PDM。它们与 Poetry 相似。我自己没有使用过它们,但我听说其他人成功地使用了它们。Hatch 似乎在库作者 (library authors) 中特别受欢迎。\n如果你正在寻找一个更强大的选项,可以处理多个子项目,Pants 构建系统在 Python 支持方面做得很好。然而,它的学习曲线相对陡峭。\n最后,如果你正在寻找一个类似 rustup 那样可以为你安装 Python 的解决方案,那么有 rye。它是新的实验性工具,但也许它对你来说是正确的选择?\n哪个是权威的工作流工具?\n如果 Python 自带一个权威的项目工作流工具会很好。很多人希望 pip 成为这样一个工具。Node.js 自带 npm,Rust 自带 Cargo,那么为什么 Python 就不能有一个呢?为什么会有这么多竞争的选择呢?\n据我所知,最大的障碍是,由于 Python 被广泛使用且用于许多不同的用例,制定一个通用的官方解决方案是困难且缓慢的(并且资金不足的)工作。另外,也不清楚 pip 是否适合这些功能。\n如果你想了解更多信息,请阅读和听取这些与我不同、深度参与 Python 社区的人的意见:\n\nStargirl (Thea Flowers) on Fediverse:《所以你想解决 Python 打包问题:一个实用指南》\nPradyun Gedam:《关于 Python 打包生态系统的思考》\nTalk Python to Me (podcast):《重新构想 Python 的打包工作流程》\n\n关于 Clojure\n阅读我的博客的 Clojure 开发者可能会问:嘿,Clojure 怎么样?为什么我们没有锁定文件呢?这是一个很好的问题!\nClojure 社区通过始终使用明确的版本而不是版本范围来解决了这个问题,即使在库中也是如此。版本描述实际上支持范围,但没有人会使用它们。这样,只要版本解析算法稳定,你总是会得到相同的版本。\n理论上,传递依赖项版本不匹配可能是一个问题,但 Clojure 支持一种编码风格,很少引起问题。\n相比之下,在 Python 和 Node.js 社区,通常期望库列出其依赖项的版本范围,而软件包管理工具会抱怨版本不匹配的问题。', 'bodyHTML': '
\n

作者:Miikka Koskinen
\n编译:沈维燕
\n时间:原文发表于 2023-10-31
\n原文:Do not use requirements.txt

\n
\n

你是否在用 Python 开发后端服务?我有两条建议:

\n
    \n
  • 不要使用 piprequirements.txt 来管理 Python 依赖。它们缺乏一些应该内置的关键功能。
  • \n
  • 改用 Poetry
  • \n
\n\n

对我来说,第一条建议毋庸置疑。第二条则更具有暂时性:Poetry 是一个很好的选择,但并非唯一值得考虑的选择。

\n

我将在下面进行解释。

\n

请注意:如果你使用 Python 做其他事情而不是构建后端服务,那么本文中的建议可能并不适用于你。例如,如果你是一个正在迁移 setup.py 的库开发者,Poetry 并不明显是一个完美的选择。

\n

PIP 缺失的功能

\n

pip 是一个工具,你可以用它从 The Python Package Index (PyPI) 中安装软件包。它随 Python 一起安装,如果你是 Python 开发者,你可能已经多次使用过它。

\n

管理 Python 项目依赖的传统方式是将它们列在一个名为 requirements.txt 的文件中,并使用 pip install -r requirements.txt 进行安装。然而,pip 被设计成一个软件包安装工具,而不是一个功能齐全的项目工作流工具。pip 缺乏两个关键功能,即依赖的锁定文件 (dependency lockfiles) 和虚拟环境的自动管理(automatic management of virtualenvs)。

\n

依赖锁定文件

\n

如果你希望在所有环境中(比如你的笔记本电脑、持续集成(CI)、生产环境)获得相同的行为,你需要锁定你的依赖项及其传递依赖的版本。你可以在 requirements.txt 中锁定你直接依赖的版本,例如,使用 requests==2.31.0 而不是 requests

\n

然而,pip 不会锁定传递依赖的版本。这可以通过使用 pip-tools 来解决,将 requirements.txt 扩展成一个列出完整依赖图的文件,包括准确版本和构件的校验和(checksums for the artifacts)。pip-tools 很不错,但你需要自行设置并弄清楚它如何适应你的工作流程。

\n

在其他编程语言中,这个功能是基本要求的 - 例如,npm 多年来一直有 package-lock.json,Cargo 也有 Cargo.lock。这个功能实在应该是一个项目工作流工具中的内置功能。

\n

虚拟环境的自动管理

\n

在 Python 中创建隔离环境的方式是使用 virtualenvs。传统上,你需要手动管理它们:通过一个 shell 命令创建一个(比如 python -m venv example 来创建名为 example 的虚拟环境),当你想要使用它时,需要用另一个 shell 命令来激活它。

\n

这容易出错:忘记激活虚拟环境或者激活错误的虚拟环境是常见的错误。有一堆的解决方法。例如,你可以使用 pyenv-virtualenv,在进入项目目录时让你的 shell 自动激活一个虚拟环境。direnv 也可以做到。

\n

同样,这也应该成为工作流工具中的一个内置功能。你不应该需要将多个工具粘合在一起。你不会听到 npm 或 Cargo 用户在虚拟环境上遇到问题的。

\n

Poetry 及其他选择

\n

幸运的是,许多人已经意识到这些问题并努力解决它们。不太幸运的是,这导致了大量的 Python 项目工作流工具涌现。那么该如何选择呢?

\n

我的建议是:选择 Poetry。它有锁定文件,有虚拟环境管理,而且很受欢迎且在积极开发中。根据我的经验,它并不完美,但是它起作用。

\n

你也可以考虑 HatchPDM。它们与 Poetry 相似。我自己没有使用过它们,但我听说其他人成功地使用了它们。Hatch 似乎在库作者 (library authors) 中特别受欢迎。

\n

如果你正在寻找一个更强大的选项,可以处理多个子项目,Pants 构建系统在 Python 支持方面做得很好。然而,它的学习曲线相对陡峭。

\n

最后,如果你正在寻找一个类似 rustup 那样可以为你安装 Python 的解决方案,那么有 rye。它是新的实验性工具,但也许它对你来说是正确的选择?

\n

哪个是权威的工作流工具?

\n

如果 Python 自带一个权威的项目工作流工具会很好。很多人希望 pip 成为这样一个工具。Node.js 自带 npm,Rust 自带 Cargo,那么为什么 Python 就不能有一个呢?为什么会有这么多竞争的选择呢?

\n

据我所知,最大的障碍是,由于 Python 被广泛使用且用于许多不同的用例,制定一个通用的官方解决方案是困难且缓慢的(并且资金不足的)工作。另外,也不清楚 pip 是否适合这些功能。

\n

如果你想了解更多信息,请阅读和听取这些与我不同、深度参与 Python 社区的人的意见:

\n\n

关于 Clojure

\n

阅读我的博客的 Clojure 开发者可能会问:嘿,Clojure 怎么样?为什么我们没有锁定文件呢?这是一个很好的问题!

\n

Clojure 社区通过始终使用明确的版本而不是版本范围来解决了这个问题,即使在库中也是如此。版本描述实际上支持范围,但没有人会使用它们。这样,只要版本解析算法稳定,你总是会得到相同的版本。

\n

理论上,传递依赖项版本不匹配可能是一个问题,但 Clojure 支持一种编码风格,很少引起问题。

\n

相比之下,在 Python 和 Node.js 社区,通常期望库列出其依赖项的版本范围,而软件包管理工具会抱怨版本不匹配的问题。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.2-编程'}, 'labels': {'nodes': [{'name': '翻译'}, {'name': '1.2.3-Python'}]}, 'comments': {'nodes': []}}, {'title': '技术人月刊(第 2 期 2024-01)', 'number': 43, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/43', 'createdAt': '2024-01-02T06:33:05Z', 'lastEditedAt': None, 'updatedAt': '2024-01-02T06:33:06Z', 'body': '## 文章', 'bodyText': '文章', 'bodyHTML': '

文章

', 'author': {'login': 'shenweiyan'}, 'category': {'name': 'x.2-月刊'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '基于 Matrix 协议的 Elements 通讯加密应用', 'number': 42, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/42', 'createdAt': '2023-12-28T09:17:08Z', 'lastEditedAt': '2023-12-30T09:56:12Z', 'updatedAt': '2023-12-30T09:56:13Z', 'body': 'Matrix 是一个开源、开放、轻量级、去中心化的即时聊天通讯协议,它是包括 deepin、Mozilla、Fedora、KDE、Archlinux、Debian 等开源社区均在广泛使用的即时聊天协议。\r\n\r\n\r\n\r\nElement 是 Matrix 官方性质的,基于 Web 技术的 Matrix 客户端实现,除了网页环境外,也有桌面客户端可用。可以在你所使用的发行版的应用商店或包管理工具中搜索 element-desktop 或近似名称来检索和安装此客户端,然后即可运行并登录你的帐号。\r\n\r\nElement 可以和 GitHub 的仓库实现关联,把 GitHub 仓库的诸多信息同步到 Element。', 'bodyText': 'Matrix 是一个开源、开放、轻量级、去中心化的即时聊天通讯协议,它是包括 deepin、Mozilla、Fedora、KDE、Archlinux、Debian 等开源社区均在广泛使用的即时聊天协议。\n\nElement 是 Matrix 官方性质的,基于 Web 技术的 Matrix 客户端实现,除了网页环境外,也有桌面客户端可用。可以在你所使用的发行版的应用商店或包管理工具中搜索 element-desktop 或近似名称来检索和安装此客户端,然后即可运行并登录你的帐号。\nElement 可以和 GitHub 的仓库实现关联,把 GitHub 仓库的诸多信息同步到 Element。', 'bodyHTML': '

Matrix 是一个开源、开放、轻量级、去中心化的即时聊天通讯协议,它是包括 deepin、Mozilla、Fedora、KDE、Archlinux、Debian 等开源社区均在广泛使用的即时聊天协议。

\n\n

Element 是 Matrix 官方性质的,基于 Web 技术的 Matrix 客户端实现,除了网页环境外,也有桌面客户端可用。可以在你所使用的发行版的应用商店或包管理工具中搜索 element-desktop 或近似名称来检索和安装此客户端,然后即可运行并登录你的帐号。

\n

Element 可以和 GitHub 的仓库实现关联,把 GitHub 仓库的诸多信息同步到 Element。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '阅读别人的博客', 'number': 41, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/41', 'createdAt': '2023-12-27T06:52:53Z', 'lastEditedAt': '2024-05-09T03:45:21Z', 'updatedAt': '2024-05-09T03:45:21Z', 'body': '很多时候阅读别人的博客(站点),总能发现一些好玩的人和事物。2023 年被[椒盐豆豉](https://blog.douchi.space/)的一篇《[2023 年了你为什么需要写博客](https://blog.douchi.space/2023-why-you-need-a-blog/)》所吸引,尤其是 **"博客是赛博空间的另一个你,也能反过来定义你"** 这一句,写出了很多心声。\r\n\r\n\r\n\r\n> 比较反感 "个人品牌" 这个过于商业化的说法,不写技术不写学术的非实名博客甚至起不到简历作用。但它确是比简历更 "像个人",比碎片化社交网络更全面展现我是怎样一个人的网络门面。当然这是我这个博客的用法,网上靠博客经营自己品牌的也比比皆是。总之,内容的自由度和高度的定制化让博客可以成为任何你想让它成为的东西。反之,博客写的久了,发现 "写博客" 也已经成为了自己(不只是线上) identity 的一部分——毕竟这是很多人认识我的渠道,也重塑了我的一部分自我认知。\r\n\r\n鉴于此,终于在个人的[站点](https://weiyan.cc/)新增加了一个[友链](https://weiyan.cc/flinks/)页面,把一部分有意思的博客与站点都以友链的方式放到了这里(会不定期清理失效域名、停更的博客)。\r\n', 'bodyText': '很多时候阅读别人的博客(站点),总能发现一些好玩的人和事物。2023 年被椒盐豆豉的一篇《2023 年了你为什么需要写博客》所吸引,尤其是 "博客是赛博空间的另一个你,也能反过来定义你" 这一句,写出了很多心声。\n\n\n比较反感 "个人品牌" 这个过于商业化的说法,不写技术不写学术的非实名博客甚至起不到简历作用。但它确是比简历更 "像个人",比碎片化社交网络更全面展现我是怎样一个人的网络门面。当然这是我这个博客的用法,网上靠博客经营自己品牌的也比比皆是。总之,内容的自由度和高度的定制化让博客可以成为任何你想让它成为的东西。反之,博客写的久了,发现 "写博客" 也已经成为了自己(不只是线上) identity 的一部分——毕竟这是很多人认识我的渠道,也重塑了我的一部分自我认知。\n\n鉴于此,终于在个人的站点新增加了一个友链页面,把一部分有意思的博客与站点都以友链的方式放到了这里(会不定期清理失效域名、停更的博客)。', 'bodyHTML': '

很多时候阅读别人的博客(站点),总能发现一些好玩的人和事物。2023 年被椒盐豆豉的一篇《2023 年了你为什么需要写博客》所吸引,尤其是 "博客是赛博空间的另一个你,也能反过来定义你" 这一句,写出了很多心声。

\n\n
\n

比较反感 "个人品牌" 这个过于商业化的说法,不写技术不写学术的非实名博客甚至起不到简历作用。但它确是比简历更 "像个人",比碎片化社交网络更全面展现我是怎样一个人的网络门面。当然这是我这个博客的用法,网上靠博客经营自己品牌的也比比皆是。总之,内容的自由度和高度的定制化让博客可以成为任何你想让它成为的东西。反之,博客写的久了,发现 "写博客" 也已经成为了自己(不只是线上) identity 的一部分——毕竟这是很多人认识我的渠道,也重塑了我的一部分自我认知。

\n
\n

鉴于此,终于在个人的站点新增加了一个友链页面,把一部分有意思的博客与站点都以友链的方式放到了这里(会不定期清理失效域名、停更的博客)。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'Pandas 处理 Excel 常用方法技巧', 'number': 40, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/40', 'createdAt': '2023-12-26T06:12:05Z', 'lastEditedAt': '2024-02-01T05:37:17Z', 'updatedAt': '2024-02-01T05:37:17Z', 'body': '在使用 Pandas 前需要学习了解一下 Series 和 DataFrame 的基本数据结构和索引的相关概念,之后就可以练习基本的 Excel操作。Pandas 读取一个 Excel 文件后会将其转化为 DataFrame 对象,每一列或行就是一个 Series 对象。这里我们看下如何对一个 excel 进行读写,以及 Sheet、行列、表头处理的一些常用技巧。\r\n\r\n## 读取 Excel\r\n\r\n如果您想读取 Excel 表格中的数据,可以使用 `read_excel()` 方法,其语法格式如下:\r\n\r\n```\r\npd.read_excel(io, sheet_name=0, header=0, names=None, index_col=None,\r\n usecols=None, squeeze=False,dtype=None, engine=None,\r\n converters=None, true_values=None, false_values=None,\r\n skiprows=None, nrows=None, na_values=None, parse_dates=False,\r\n date_parser=None, thousands=None, comment=None, skipfooter=0,\r\n convert_float=True, **kwds)\r\n```\r\n\r\n下表对常用参数做了说明:\r\n\r\n|参数名称|说明|\r\n|:----|:----|\r\n|io|表示 Excel 文件的存储路径。|\r\n|sheet_name|要读取的工作表名称,默认0,即读取第一个工作表作为 DataFrame(一定要加`sheet_name=None`,才能读取出所有的 sheet,否则默认读取第一个 sheet)。|\r\n|header|指定作为列名的行,默认0,即取第一行的值为列名;若数据不包含列名,则设定 header = None。若将其设置为 header=2,则表示将前两行作为多重索引。|\r\n|names|一般适用于Excel缺少列名,或者需要重新定义列名的情况;names的长度必须等于Excel表格列的长度,否则会报错。|\r\n|index_col|用做行索引的列,可以是工作表的列名称,如 index_col = \'列名\',也可以是整数或者列表。|\r\n|usecols|int或list类型,默认为None,表示需要读取所有列。|\r\n|squeeze|boolean,默认为False,如果解析的数据只包含一列,则返回一个Series。|\r\n|converters|规定每一列的数据类型。|\r\n|skiprows|接受一个列表,表示跳过指定行数的数据,从头部第一行开始。|\r\n|nrows|需要读取的行数。|\r\n|skipfooter|接受一个列表,省略指定行数的数据,从尾部最后一行开始。|\r\n\r\n示例如下所示:\r\n```python\r\nimport pandas as pd\r\n\r\n# 读取所有Sheet\r\ndf = pd.read_excel(\'example.xlsx\', sheet_name=None)\r\n\r\n# 读取第一个、第二个和名为"Sheet5"的工作表作为 DataFrame 的字典\r\ndf = pd.read_excel(\'example.xlsx\', sheet_name=[0, 1, "Sheet5"])\r\n```\r\n\r\n## 获取行数和列数\r\n```python\r\nimport pandas as pd\r\n \r\ndf = pd.read_excel(\'example.xlsx\')\r\n# 行索引\r\nprint(df.index) \r\n# RangeIndex(start=0, stop=3747, step=1)\r\n\r\n# 输出元祖,分别为行数和列数,默认第一行是表头不算行数\r\nprint(df.shape) \r\n# (3747, 4)\r\n```\r\n\r\n## 获取表头\r\n`read_excel` 默认是把 excel 的第一行当成表头。注意:如果 `read_excel` 的 `sheet_name=None`,读取的是所有 excel 的 sheet_name(key) 和 sheet_values(values) 组成的字典,`df.keys()` 的结果是所有 sheet_name,即名字(字典的键)。\r\n\r\n### 获取第一个 sheet\r\n这时候 `df.keys()` 和 `df.columns` 的结果是一样的,都是第一个 sheet 的表头。\r\n\r\n```python\r\nimport pandas as pd\r\n \r\ndf = pd.read_excel(\'input.xlsx\')\r\nprint(df.keys())\r\nprint(\'---------------\')\r\nprint(df.columns)\r\n```\r\n\r\n### 获取所有 sheet\r\n```python\r\nimport pandas as pd\r\n \r\n# 参数为 None 代表读取所有 sheet\r\ndf = pd.read_excel(\'input.xlsx\',sheet_name=None)\r\n\r\n# 获取所有sheet名字, 如果read_excel参数不是None, 则df.keys()为表头\r\nsheet_names = list(df.keys())\r\nprint(sheet_names)\r\n```\r\n\r\n## 参考资料\r\n1. 老董,《[pandas获取excel的行数,列数,表头,sheet,前后行等数据](https://www.python66.com/pandasshujufenxi/268.html)》,[Python编程网](https://www.python66.com/)\r\n2. 《[Pandas Excel读写操作详解](https://c.biancheng.net/pandas/excel.html)》,[C语言中文网](https://c.biancheng.net/)\r\n3. 《[pandas.read_excel — pandas 2.1.4 documentation](https://pandas.pydata.org/docs/reference/api/pandas.read_excel.html)》,[pandas documentation — pandas 2.1.4 documentation](https://pandas.pydata.org/docs/index.html)', 'bodyText': '在使用 Pandas 前需要学习了解一下 Series 和 DataFrame 的基本数据结构和索引的相关概念,之后就可以练习基本的 Excel操作。Pandas 读取一个 Excel 文件后会将其转化为 DataFrame 对象,每一列或行就是一个 Series 对象。这里我们看下如何对一个 excel 进行读写,以及 Sheet、行列、表头处理的一些常用技巧。\n读取 Excel\n如果您想读取 Excel 表格中的数据,可以使用 read_excel() 方法,其语法格式如下:\npd.read_excel(io, sheet_name=0, header=0, names=None, index_col=None,\n usecols=None, squeeze=False,dtype=None, engine=None,\n converters=None, true_values=None, false_values=None,\n skiprows=None, nrows=None, na_values=None, parse_dates=False,\n date_parser=None, thousands=None, comment=None, skipfooter=0,\n convert_float=True, **kwds)\n\n下表对常用参数做了说明:\n\n\n\n参数名称\n说明\n\n\n\n\nio\n表示 Excel 文件的存储路径。\n\n\nsheet_name\n要读取的工作表名称,默认0,即读取第一个工作表作为 DataFrame(一定要加sheet_name=None,才能读取出所有的 sheet,否则默认读取第一个 sheet)。\n\n\nheader\n指定作为列名的行,默认0,即取第一行的值为列名;若数据不包含列名,则设定 header = None。若将其设置为 header=2,则表示将前两行作为多重索引。\n\n\nnames\n一般适用于Excel缺少列名,或者需要重新定义列名的情况;names的长度必须等于Excel表格列的长度,否则会报错。\n\n\nindex_col\n用做行索引的列,可以是工作表的列名称,如 index_col = \'列名\',也可以是整数或者列表。\n\n\nusecols\nint或list类型,默认为None,表示需要读取所有列。\n\n\nsqueeze\nboolean,默认为False,如果解析的数据只包含一列,则返回一个Series。\n\n\nconverters\n规定每一列的数据类型。\n\n\nskiprows\n接受一个列表,表示跳过指定行数的数据,从头部第一行开始。\n\n\nnrows\n需要读取的行数。\n\n\nskipfooter\n接受一个列表,省略指定行数的数据,从尾部最后一行开始。\n\n\n\n示例如下所示:\nimport pandas as pd\n\n# 读取所有Sheet\ndf = pd.read_excel(\'example.xlsx\', sheet_name=None)\n\n# 读取第一个、第二个和名为"Sheet5"的工作表作为 DataFrame 的字典\ndf = pd.read_excel(\'example.xlsx\', sheet_name=[0, 1, "Sheet5"])\n获取行数和列数\nimport pandas as pd\n \ndf = pd.read_excel(\'example.xlsx\')\n# 行索引\nprint(df.index) \n# RangeIndex(start=0, stop=3747, step=1)\n\n# 输出元祖,分别为行数和列数,默认第一行是表头不算行数\nprint(df.shape) \n# (3747, 4)\n获取表头\nread_excel 默认是把 excel 的第一行当成表头。注意:如果 read_excel 的 sheet_name=None,读取的是所有 excel 的 sheet_name(key) 和 sheet_values(values) 组成的字典,df.keys() 的结果是所有 sheet_name,即名字(字典的键)。\n获取第一个 sheet\n这时候 df.keys() 和 df.columns 的结果是一样的,都是第一个 sheet 的表头。\nimport pandas as pd\n \ndf = pd.read_excel(\'input.xlsx\')\nprint(df.keys())\nprint(\'---------------\')\nprint(df.columns)\n获取所有 sheet\nimport pandas as pd\n \n# 参数为 None 代表读取所有 sheet\ndf = pd.read_excel(\'input.xlsx\',sheet_name=None)\n\n# 获取所有sheet名字, 如果read_excel参数不是None, 则df.keys()为表头\nsheet_names = list(df.keys())\nprint(sheet_names)\n参考资料\n\n老董,《pandas获取excel的行数,列数,表头,sheet,前后行等数据》,Python编程网\n《Pandas Excel读写操作详解》,C语言中文网\n《pandas.read_excel — pandas 2.1.4 documentation》,pandas documentation — pandas 2.1.4 documentation', 'bodyHTML': '

在使用 Pandas 前需要学习了解一下 Series 和 DataFrame 的基本数据结构和索引的相关概念,之后就可以练习基本的 Excel操作。Pandas 读取一个 Excel 文件后会将其转化为 DataFrame 对象,每一列或行就是一个 Series 对象。这里我们看下如何对一个 excel 进行读写,以及 Sheet、行列、表头处理的一些常用技巧。

\n

读取 Excel

\n

如果您想读取 Excel 表格中的数据,可以使用 read_excel() 方法,其语法格式如下:

\n
pd.read_excel(io, sheet_name=0, header=0, names=None, index_col=None,\n              usecols=None, squeeze=False,dtype=None, engine=None,\n              converters=None, true_values=None, false_values=None,\n              skiprows=None, nrows=None, na_values=None, parse_dates=False,\n              date_parser=None, thousands=None, comment=None, skipfooter=0,\n              convert_float=True, **kwds)\n
\n

下表对常用参数做了说明:

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
参数名称说明
io表示 Excel 文件的存储路径。
sheet_name要读取的工作表名称,默认0,即读取第一个工作表作为 DataFrame(一定要加sheet_name=None,才能读取出所有的 sheet,否则默认读取第一个 sheet)。
header指定作为列名的行,默认0,即取第一行的值为列名;若数据不包含列名,则设定 header = None。若将其设置为 header=2,则表示将前两行作为多重索引。
names一般适用于Excel缺少列名,或者需要重新定义列名的情况;names的长度必须等于Excel表格列的长度,否则会报错。
index_col用做行索引的列,可以是工作表的列名称,如 index_col = \'列名\',也可以是整数或者列表。
usecolsint或list类型,默认为None,表示需要读取所有列。
squeezeboolean,默认为False,如果解析的数据只包含一列,则返回一个Series。
converters规定每一列的数据类型。
skiprows接受一个列表,表示跳过指定行数的数据,从头部第一行开始。
nrows需要读取的行数。
skipfooter接受一个列表,省略指定行数的数据,从尾部最后一行开始。
\n

示例如下所示:

\n
import pandas as pd\n\n# 读取所有Sheet\ndf = pd.read_excel(\'example.xlsx\', sheet_name=None)\n\n# 读取第一个、第二个和名为"Sheet5"的工作表作为 DataFrame 的字典\ndf = pd.read_excel(\'example.xlsx\', sheet_name=[0, 1, "Sheet5"])
\n

获取行数和列数

\n
import pandas as pd\n \ndf = pd.read_excel(\'example.xlsx\')\n# 行索引\nprint(df.index)  \n# RangeIndex(start=0, stop=3747, step=1)\n\n# 输出元祖,分别为行数和列数,默认第一行是表头不算行数\nprint(df.shape) \n# (3747, 4)
\n

获取表头

\n

read_excel 默认是把 excel 的第一行当成表头。注意:如果 read_excelsheet_name=None,读取的是所有 excel 的 sheet_name(key) 和 sheet_values(values) 组成的字典,df.keys() 的结果是所有 sheet_name,即名字(字典的键)。

\n

获取第一个 sheet

\n

这时候 df.keys()df.columns 的结果是一样的,都是第一个 sheet 的表头。

\n
import pandas as pd\n \ndf = pd.read_excel(\'input.xlsx\')\nprint(df.keys())\nprint(\'---------------\')\nprint(df.columns)
\n

获取所有 sheet

\n
import pandas as pd\n \n# 参数为 None 代表读取所有 sheet\ndf = pd.read_excel(\'input.xlsx\',sheet_name=None)\n\n# 获取所有sheet名字, 如果read_excel参数不是None, 则df.keys()为表头\nsheet_names = list(df.keys())\nprint(sheet_names)
\n

参考资料

\n
    \n
  1. 老董,《pandas获取excel的行数,列数,表头,sheet,前后行等数据》,Python编程网
  2. \n
  3. Pandas Excel读写操作详解》,C语言中文网
  4. \n
  5. pandas.read_excel — pandas 2.1.4 documentation》,pandas documentation — pandas 2.1.4 documentation
  6. \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.2-编程'}, 'labels': {'nodes': [{'name': '1.2.3-Python'}]}, 'comments': {'nodes': []}}, {'title': '跳过任意开屏广告和内部弹窗广告', 'number': 39, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/39', 'createdAt': '2023-12-06T03:50:28Z', 'lastEditedAt': '2023-12-08T05:31:46Z', 'updatedAt': '2024-01-04T05:42:23Z', 'body': '今天去用了一下 [gkd](https://github.com/gkd-kit/gkd)—— 点击跳过任意开屏广告/点击关闭应用内部任意弹窗广告的应用,发现真不错,记录一下遇到的一些问题。\r\n\r\n\r\n\r\n具体使用步骤如下。\r\n\r\n## 1. 开启权限\r\n\r\n应用安装后,**"主页"** 页面的这几个权限都需要开启(尤其是**无障碍权限**),否则应用无法跳过广告,不起作用。 \r\n\r\ngkd-home\r\n\r\n华为鸿蒙系统怎么开启无障碍模式(也可以参考:[通过快捷方式启动无障碍功能](https://consumer.huawei.com/cn/support/content/zh-cn15849085/)): \r\n \r\n1. 打开辅助功能,进入手机设置界面,点击【辅助功能】。\r\n2. 打开无障碍,点击【无障碍】。\r\n3. 打开已安装的服务,下拉到页面底部,点击【已安装的服务】。\r\n4. 选择服务,选择要设置的服务【GKD】,点击进入。\r\n5. 打开服务开关,点击服务右侧【开关】按钮。\r\n6. 确定打开。\r\n\r\n这里会有一个问题:**鸿蒙手机无障碍打开后,点击清理后台会自动关闭**!参考:[gkd-kit/gkd#201](https://github.com/gkd-kit/gkd/issues/201)\r\n\r\n具体可以参考华为官方给出的解决方法——《[华为手机/平板无障碍中的第三方应用的服务开关自动关闭](https://consumer.huawei.com/cn/support/content/zh-cn00410039/)》。\r\n\r\n\r\n## 2. 更新订阅\r\n\r\n应用安装后,**"订阅"** 页面的本地订阅如果没有规则,则需要下拉执行更新一下即可(参考:[gkd-kit/gkd#100](https://github.com/gkd-kit/gkd/issues/100))。\r\n\r\nGKD-订阅\r\n\r\n## 3. 设置\r\n\r\n这是个人在使用时候 **"设置"** 页面的一个截图。 \r\n\r\nGKD-订阅\r\n', 'bodyText': '今天去用了一下 gkd—— 点击跳过任意开屏广告/点击关闭应用内部任意弹窗广告的应用,发现真不错,记录一下遇到的一些问题。\n\n具体使用步骤如下。\n1. 开启权限\n应用安装后,"主页" 页面的这几个权限都需要开启(尤其是无障碍权限),否则应用无法跳过广告,不起作用。\n\n华为鸿蒙系统怎么开启无障碍模式(也可以参考:通过快捷方式启动无障碍功能):\n\n打开辅助功能,进入手机设置界面,点击【辅助功能】。\n打开无障碍,点击【无障碍】。\n打开已安装的服务,下拉到页面底部,点击【已安装的服务】。\n选择服务,选择要设置的服务【GKD】,点击进入。\n打开服务开关,点击服务右侧【开关】按钮。\n确定打开。\n\n这里会有一个问题:鸿蒙手机无障碍打开后,点击清理后台会自动关闭!参考:gkd-kit/gkd#201\n具体可以参考华为官方给出的解决方法——《华为手机/平板无障碍中的第三方应用的服务开关自动关闭》。\n2. 更新订阅\n应用安装后,"订阅" 页面的本地订阅如果没有规则,则需要下拉执行更新一下即可(参考:gkd-kit/gkd#100)。\n\n3. 设置\n这是个人在使用时候 "设置" 页面的一个截图。', 'bodyHTML': '

今天去用了一下 gkd—— 点击跳过任意开屏广告/点击关闭应用内部任意弹窗广告的应用,发现真不错,记录一下遇到的一些问题。

\n\n

具体使用步骤如下。

\n

1. 开启权限

\n

应用安装后,"主页" 页面的这几个权限都需要开启(尤其是无障碍权限),否则应用无法跳过广告,不起作用。

\n

gkd-home

\n

华为鸿蒙系统怎么开启无障碍模式(也可以参考:通过快捷方式启动无障碍功能):

\n
    \n
  1. 打开辅助功能,进入手机设置界面,点击【辅助功能】。
  2. \n
  3. 打开无障碍,点击【无障碍】。
  4. \n
  5. 打开已安装的服务,下拉到页面底部,点击【已安装的服务】。
  6. \n
  7. 选择服务,选择要设置的服务【GKD】,点击进入。
  8. \n
  9. 打开服务开关,点击服务右侧【开关】按钮。
  10. \n
  11. 确定打开。
  12. \n
\n

这里会有一个问题:鸿蒙手机无障碍打开后,点击清理后台会自动关闭!参考:gkd-kit/gkd#201

\n

具体可以参考华为官方给出的解决方法——《华为手机/平板无障碍中的第三方应用的服务开关自动关闭》。

\n

2. 更新订阅

\n

应用安装后,"订阅" 页面的本地订阅如果没有规则,则需要下拉执行更新一下即可(参考:gkd-kit/gkd#100)。

\n

GKD-订阅

\n

3. 设置

\n

这是个人在使用时候 "设置" 页面的一个截图。

\n

GKD-订阅

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': [{'body': '首页的那个猫咪有意思~~', 'author': {'login': 'obaby'}}]}}, {'title': 'GitHub Discussions 使用与思考', 'number': 38, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/38', 'createdAt': '2023-12-06T01:55:19Z', 'lastEditedAt': '2024-03-18T06:25:33Z', 'updatedAt': '2024-03-18T06:25:33Z', 'body': '从2023年7月起我所有可公开的文档都保存在了 [GitHub Discussions](https://github.com/shenweiyan/Knowledge-Garden/discussions) 上,作为博客、IED 编辑器,以及评论使用,GitHub Discussions 是完全没问题的。\r\n\r\n\r\n\r\n## 开源的代名词\r\n\r\n开源已成为 GitHub 的代名词。\r\n\r\n> 当开发者谈论开源时,通常会想到 GitHub,它不仅仅是一个代码托管平台,更是一个汇聚了全球开发者的社交中心。过去,开发者发布一款软件后,都是在自己的小圈子里默默努力和交流,现在通过 GitHub 平台可以方便地与全球的开发者分享、交流和协作。贡献者在这里展示自己的才华,追随者在这里寻找强者的脚印,等待着被世人认可的时刻。\r\n\r\n## 体验与感受\r\n\r\n由于 GitHub 是直接 markdown 源码进行书写,正常的导出基本不会有格式错乱的问题,这一点非常好。不像有一些富文本的编辑器,动不动就给你增加几个换行或者空格什么的额外字符。\r\n\r\n借助 GitHub GraphQL API + Python + GitHub Actions 进行每天定时导出非常顺滑,导出来的文档可以随意折腾,自由度非常大。\r\n\r\n## 专业书籍文档\r\n\r\n今天忽然想到的一个问题,即如果作为专业性比较强的系列文档写作,如《[Hello 算法](https://www.hello-algo.com/)》 这样专业性和逻辑性非常明确的专业书籍,使用 GitHub Discussions 写作应该是有点不太合适。\r\n\r\n但又仔细想了一下,如果**只是写作**应该是没问题的 —— 我们可以用 sections 或者 categories,甚至是 tags 进行书籍分类,最后在导出的时候借助这些标签把相关的文档整合到一块,再借助 nav 梳理成大纲展现给读者阅读就可以。所以,总的来说可以用于专业书籍**写作(编辑)**,但**不太适合用于专业书籍的呈现和阅读** —— 主要是大纲和逻辑性会变得不明显。\r\n\r\n## 目录和分类标签\r\n\r\nGitHub Discussions 目前[最多支持 25 个 categories](https://github.com/orgs/community/discussions/7960),这是一个限制。因此,通过 section+category 我们在 Discussions 上最多只能实现两级的目录结构,所以对于三级和三级以上的目录结构目前暂时无能为力。\r\n\r\n因此,想到一个折中的解决方法:使用 labels 来区分第三级目录结构。\r\n```\r\n1.1-生信\r\n - 1.1.1-算法\r\n - 1.1.2-数据\r\n - 1.1.2-软件\r\n```\r\n\r\n然后,导出 Discussions 的时候需要在本地先在本地建立一个 `section+category: dictory` 一一对应的字典,最后通过这个字典把不同的讨论 md 归档至对应的目录。\r\n```\r\n1.1-生信:\r\n 1.1.1-算法: docs/cookbook/生物信息/算法\r\n 1.1.2-数据: docs/cookbook/生物信息/数据\r\n 1.1.2-软件: docs/cookbook/生物信息/软件\r\n ...\r\n```\r\n\r\n## GitHub GraphQL API\r\n\r\nGitHub Discussions 的 API 操作主要依赖 [GitHub GraphQL API](https://docs.github.com/zh/graphql/overview/about-the-graphql-api)。\r\n\r\n> ## 概述\r\n> \r\n> GraphQL 是一种用于[应用编程接口(API)](https://www.redhat.com/zh/topics/api/what-are-application-programming-interfaces)的查询语言和服务器端运行时,它可以使客户端准确地获得所需的数据,没有任何冗余。\r\n> \r\n> ## GraphQL 有什么用? \r\n> GraphQL 旨在让 API 变得快速、灵活并且为开发人员提供便利。它甚至可以部署在名为 [GraphiQL](https://github.com/graphql/graphiql) 的[集成开发环境(IDE)](https://www.redhat.com/zh/topics/middleware/what-is-ide)中。作为 [REST](https://www.redhat.com/zh/topics/integration/whats-the-difference-between-soap-rest) 的替代方案,GraphQL 允许开发人员构建相应的请求,从而通过单个 API 调用从多个数据源中提取数据。\r\n> \r\n> 此外,GraphQL 还可让 API 维护人员灵活地添加或弃用字段,而不会影响现有查询。开发人员可以使用自己喜欢的方法来构建 API,并且 GraphQL 规范将确保它们以可预测的方式在客户端发挥作用。\r\n> \r\n> From:《[什么是 GraphQL?核心概念解析](https://www.redhat.com/zh/topics/api/what-is-graphql)》- 红帽\r\n\r\n- 中文文档:https://docs.github.com/zh/graphql/guides/introduction-to-graphql\r\n- 在线使用:https://docs.github.com/en/graphql/overview/explorer\r\n\r\n### 获取 discussions 主要信息\r\n```\r\n{\r\n repository(owner: "shenweiyan", name: "Knowledge-Garden") {\r\n discussions(orderBy: {field: CREATED_AT, direction: DESC}, categoryId: null, first: 5) {\r\n nodes {\r\n title\r\n number\r\n url\r\n createdAt\r\n lastEditedAt\r\n updatedAt\r\n body\r\n bodyText\r\n bodyHTML\r\n author {\r\n login\r\n }\r\n category {\r\n name\r\n }\r\n labels(first: 100) {\r\n nodes {\r\n name\r\n }\r\n }\r\n comments(first: 10) {\r\n nodes {\r\n body\r\n author {\r\n login\r\n }\r\n }\r\n }\r\n }\r\n pageInfo {\r\n hasNextPage\r\n endCursor\r\n }\r\n }\r\n }\r\n}\r\n```\r\n\r\n\r\n### 获取 discussions categoryId\r\n\r\n参考:《[how to get github discussions categoryId](https://qiita.com/shooter/items/d59fbb43d0f118c95092)》\r\n\r\n```\r\n{\r\n repository(owner: "shenweiyan", name: "Knowledge-Garden") {\r\n id\r\n name\r\n discussionCategories(first: 30) {\r\n nodes {\r\n id\r\n name\r\n }\r\n }\r\n }\r\n}\r\n```\r\n\r\n### 其他的一些问题\r\n\r\n目前,通过 GitHub GraphQL API 暂时无法获取 Sections 的信息。\r\n\r\n## 简单的总结\r\n\r\n拥抱 GitHub Discussions 的一个前提是你可以随时登录 GitHub,如果你已经解决了这个问题,也想着像我一样 Using Github discussions as your blog engine,那么你可以参考一下我的 [shenweiyan/Knowledge-Garden](https://github.com/shenweiyan/Knowledge-Garden/) 仓库。', 'bodyText': '从2023年7月起我所有可公开的文档都保存在了 GitHub Discussions 上,作为博客、IED 编辑器,以及评论使用,GitHub Discussions 是完全没问题的。\n\n开源的代名词\n开源已成为 GitHub 的代名词。\n\n当开发者谈论开源时,通常会想到 GitHub,它不仅仅是一个代码托管平台,更是一个汇聚了全球开发者的社交中心。过去,开发者发布一款软件后,都是在自己的小圈子里默默努力和交流,现在通过 GitHub 平台可以方便地与全球的开发者分享、交流和协作。贡献者在这里展示自己的才华,追随者在这里寻找强者的脚印,等待着被世人认可的时刻。\n\n体验与感受\n由于 GitHub 是直接 markdown 源码进行书写,正常的导出基本不会有格式错乱的问题,这一点非常好。不像有一些富文本的编辑器,动不动就给你增加几个换行或者空格什么的额外字符。\n借助 GitHub GraphQL API + Python + GitHub Actions 进行每天定时导出非常顺滑,导出来的文档可以随意折腾,自由度非常大。\n专业书籍文档\n今天忽然想到的一个问题,即如果作为专业性比较强的系列文档写作,如《Hello 算法》 这样专业性和逻辑性非常明确的专业书籍,使用 GitHub Discussions 写作应该是有点不太合适。\n但又仔细想了一下,如果只是写作应该是没问题的 —— 我们可以用 sections 或者 categories,甚至是 tags 进行书籍分类,最后在导出的时候借助这些标签把相关的文档整合到一块,再借助 nav 梳理成大纲展现给读者阅读就可以。所以,总的来说可以用于专业书籍写作(编辑),但不太适合用于专业书籍的呈现和阅读 —— 主要是大纲和逻辑性会变得不明显。\n目录和分类标签\nGitHub Discussions 目前最多支持 25 个 categories,这是一个限制。因此,通过 section+category 我们在 Discussions 上最多只能实现两级的目录结构,所以对于三级和三级以上的目录结构目前暂时无能为力。\n因此,想到一个折中的解决方法:使用 labels 来区分第三级目录结构。\n1.1-生信\n - 1.1.1-算法\n - 1.1.2-数据\n - 1.1.2-软件\n\n然后,导出 Discussions 的时候需要在本地先在本地建立一个 section+category: dictory 一一对应的字典,最后通过这个字典把不同的讨论 md 归档至对应的目录。\n1.1-生信:\n 1.1.1-算法: docs/cookbook/生物信息/算法\n 1.1.2-数据: docs/cookbook/生物信息/数据\n 1.1.2-软件: docs/cookbook/生物信息/软件\n ...\n\nGitHub GraphQL API\nGitHub Discussions 的 API 操作主要依赖 GitHub GraphQL API。\n\n概述\nGraphQL 是一种用于应用编程接口(API)的查询语言和服务器端运行时,它可以使客户端准确地获得所需的数据,没有任何冗余。\nGraphQL 有什么用?\nGraphQL 旨在让 API 变得快速、灵活并且为开发人员提供便利。它甚至可以部署在名为 GraphiQL 的集成开发环境(IDE)中。作为 REST 的替代方案,GraphQL 允许开发人员构建相应的请求,从而通过单个 API 调用从多个数据源中提取数据。\n此外,GraphQL 还可让 API 维护人员灵活地添加或弃用字段,而不会影响现有查询。开发人员可以使用自己喜欢的方法来构建 API,并且 GraphQL 规范将确保它们以可预测的方式在客户端发挥作用。\nFrom:《什么是 GraphQL?核心概念解析》- 红帽\n\n\n中文文档:https://docs.github.com/zh/graphql/guides/introduction-to-graphql\n在线使用:https://docs.github.com/en/graphql/overview/explorer\n\n获取 discussions 主要信息\n{\n repository(owner: "shenweiyan", name: "Knowledge-Garden") {\n discussions(orderBy: {field: CREATED_AT, direction: DESC}, categoryId: null, first: 5) {\n nodes {\n title\n number\n url\n createdAt\n lastEditedAt\n updatedAt\n body\n bodyText\n bodyHTML\n author {\n login\n }\n category {\n name\n }\n labels(first: 100) {\n nodes {\n name\n }\n }\n comments(first: 10) {\n nodes {\n body\n author {\n login\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n }\n}\n\n获取 discussions categoryId\n参考:《how to get github discussions categoryId》\n{\n repository(owner: "shenweiyan", name: "Knowledge-Garden") {\n id\n name\n discussionCategories(first: 30) {\n nodes {\n id\n name\n }\n }\n }\n}\n\n其他的一些问题\n目前,通过 GitHub GraphQL API 暂时无法获取 Sections 的信息。\n简单的总结\n拥抱 GitHub Discussions 的一个前提是你可以随时登录 GitHub,如果你已经解决了这个问题,也想着像我一样 Using Github discussions as your blog engine,那么你可以参考一下我的 shenweiyan/Knowledge-Garden 仓库。', 'bodyHTML': '

从2023年7月起我所有可公开的文档都保存在了 GitHub Discussions 上,作为博客、IED 编辑器,以及评论使用,GitHub Discussions 是完全没问题的。

\n\n

开源的代名词

\n

开源已成为 GitHub 的代名词。

\n
\n

当开发者谈论开源时,通常会想到 GitHub,它不仅仅是一个代码托管平台,更是一个汇聚了全球开发者的社交中心。过去,开发者发布一款软件后,都是在自己的小圈子里默默努力和交流,现在通过 GitHub 平台可以方便地与全球的开发者分享、交流和协作。贡献者在这里展示自己的才华,追随者在这里寻找强者的脚印,等待着被世人认可的时刻。

\n
\n

体验与感受

\n

由于 GitHub 是直接 markdown 源码进行书写,正常的导出基本不会有格式错乱的问题,这一点非常好。不像有一些富文本的编辑器,动不动就给你增加几个换行或者空格什么的额外字符。

\n

借助 GitHub GraphQL API + Python + GitHub Actions 进行每天定时导出非常顺滑,导出来的文档可以随意折腾,自由度非常大。

\n

专业书籍文档

\n

今天忽然想到的一个问题,即如果作为专业性比较强的系列文档写作,如《Hello 算法》 这样专业性和逻辑性非常明确的专业书籍,使用 GitHub Discussions 写作应该是有点不太合适。

\n

但又仔细想了一下,如果只是写作应该是没问题的 —— 我们可以用 sections 或者 categories,甚至是 tags 进行书籍分类,最后在导出的时候借助这些标签把相关的文档整合到一块,再借助 nav 梳理成大纲展现给读者阅读就可以。所以,总的来说可以用于专业书籍写作(编辑),但不太适合用于专业书籍的呈现和阅读 —— 主要是大纲和逻辑性会变得不明显。

\n

目录和分类标签

\n

GitHub Discussions 目前最多支持 25 个 categories,这是一个限制。因此,通过 section+category 我们在 Discussions 上最多只能实现两级的目录结构,所以对于三级和三级以上的目录结构目前暂时无能为力。

\n

因此,想到一个折中的解决方法:使用 labels 来区分第三级目录结构。

\n
1.1-生信\n  - 1.1.1-算法\n  - 1.1.2-数据\n  - 1.1.2-软件\n
\n

然后,导出 Discussions 的时候需要在本地先在本地建立一个 section+category: dictory 一一对应的字典,最后通过这个字典把不同的讨论 md 归档至对应的目录。

\n
1.1-生信:\n    1.1.1-算法: docs/cookbook/生物信息/算法\n    1.1.2-数据: docs/cookbook/生物信息/数据\n    1.1.2-软件: docs/cookbook/生物信息/软件\n    ...\n
\n

GitHub GraphQL API

\n

GitHub Discussions 的 API 操作主要依赖 GitHub GraphQL API

\n
\n

概述

\n

GraphQL 是一种用于应用编程接口(API)的查询语言和服务器端运行时,它可以使客户端准确地获得所需的数据,没有任何冗余。

\n

GraphQL 有什么用?

\n

GraphQL 旨在让 API 变得快速、灵活并且为开发人员提供便利。它甚至可以部署在名为 GraphiQL集成开发环境(IDE)中。作为 REST 的替代方案,GraphQL 允许开发人员构建相应的请求,从而通过单个 API 调用从多个数据源中提取数据。

\n

此外,GraphQL 还可让 API 维护人员灵活地添加或弃用字段,而不会影响现有查询。开发人员可以使用自己喜欢的方法来构建 API,并且 GraphQL 规范将确保它们以可预测的方式在客户端发挥作用。

\n

From:《什么是 GraphQL?核心概念解析》- 红帽

\n
\n\n

获取 discussions 主要信息

\n
{\n  repository(owner: "shenweiyan", name: "Knowledge-Garden") {\n    discussions(orderBy: {field: CREATED_AT, direction: DESC}, categoryId: null, first: 5) {\n      nodes {\n        title\n        number\n        url\n        createdAt\n        lastEditedAt\n        updatedAt\n        body\n        bodyText\n        bodyHTML\n        author {\n          login\n        }\n        category {\n          name\n        }\n        labels(first: 100) {\n          nodes {\n            name\n          }\n        }\n        comments(first: 10) {\n          nodes {\n            body\n            author {\n              login\n            }\n          }\n        }\n      }\n      pageInfo {\n        hasNextPage\n        endCursor\n      }\n    }\n  }\n}\n
\n

获取 discussions categoryId

\n

参考:《how to get github discussions categoryId

\n
{\n  repository(owner: "shenweiyan", name: "Knowledge-Garden") {\n    id\n    name\n    discussionCategories(first: 30) {\n      nodes {\n        id\n        name\n      }\n    }\n  }\n}\n
\n

其他的一些问题

\n

目前,通过 GitHub GraphQL API 暂时无法获取 Sections 的信息。

\n

简单的总结

\n

拥抱 GitHub Discussions 的一个前提是你可以随时登录 GitHub,如果你已经解决了这个问题,也想着像我一样 Using Github discussions as your blog engine,那么你可以参考一下我的 shenweiyan/Knowledge-Garden 仓库。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': [{'name': '公众号'}]}, 'comments': {'nodes': []}}, {'title': 'MkDocs Material 安装部署和使用', 'number': 37, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/37', 'createdAt': '2023-12-06T01:28:00Z', 'lastEditedAt': '2023-12-11T02:08:45Z', 'updatedAt': '2024-01-04T05:42:38Z', 'body': 'MkDocs 是一个快速、简单、华丽的静态网站生成器,适用于构建项目文档。文档源文件以 Markdown 编写,并使用一个 YAML 文件来进行配置。[Material for MkDocs](https://squidfunk.github.io/mkdocs-material/) 是 [MkDocs](https://www.mkdocs.org/) 的一个主题配置,更加简洁美观,更新和维护也更加及时和频繁,且社区也更加活跃。\r\n\r\n\r\n\r\n## 安装\r\n\r\n主要使用的一些软件包以及模块 (requirements.txt) 如下:\r\n```\r\nmkdocs==1.5.3\r\nmkdocs-material\r\nmkdocs-rss-plugin\r\nmkdocs-git-revision-date-plugin\r\nmkdocs-include-dir-to-nav==1.2.0\r\nmkdocs-glightbox\r\njieba\r\n```\r\n\r\n```\r\npip3 install -r requirements.txt\r\n```\r\n\r\n查看 `mkdocs-material`, `mkdocs` 的版本:\r\n```python\r\n$ mkdocs --version\r\nmkdocs, version 1.5.3 from /usr/local/software/python-3.9.18/lib/python3.9/site-packages/mkdocs (Python 3.9)\r\n\r\n$ pip3 show mkdocs-material\r\nName: mkdocs-material\r\nVersion: 9.4.4\r\nSummary: Documentation that simply works\r\nHome-page: \r\nAuthor: \r\nAuthor-email: Martin Donath \r\nLicense: \r\nLocation: /usr/local/software/python-3.9.18/lib/python3.9/site-packages\r\nRequires: babel, colorama, jinja2, markdown, mkdocs, mkdocs-material-extensions, paginate, pygments, pymdown-extensions, regex, requests\r\nRequired-by:\r\n```\r\n\r\n## 使用\r\n\r\n本地预览:\r\n```\r\n$ mkdocs serve -a 0.0.0.0:8000\r\n```\r\n\r\n## 问题与解决\r\n\r\n1. Pagination 分页与 `git-revision-date` 冲突,导致无法构建 - 参考 [mkdocs-material/discussions/6156](https://github.com/squidfunk/mkdocs-material/discussions/6156)\r\n2. [Support Markdown in the copyright string #5134](https://github.com/squidfunk/mkdocs-material/issues/5134)\r\n3. [如何在 MkDocs 的版权部分自动添加年份 - squidfunk/mkdocs-material#4969](https://github.com/squidfunk/mkdocs-material/discussions/4969)\r\n4. [如何定制博客插件的归档页面 - squidfunk/mkdocs-material#6324](https://github.com/squidfunk/mkdocs-material/discussions/6324)\r\n\r\n## 期待的功能\r\n\r\n这是一个个人非常期待的功能,大部分目前已经可以在 [Insiders](https://squidfunk.github.io/mkdocs-material/insiders/) 版本中使用,社区公开的版本尚无法使用。\r\n\r\n- 博客插件的自定义归档、目录页面每页文档数 - [squidfunk/mkdocs-material#6383](https://github.com/squidfunk/mkdocs-material/issues/6383)\r\n- 内置隐私插件(方便内网/国内部署加速访问)- [Built-in privacy plugin - Material for MkDocs](https://squidfunk.github.io/mkdocs-material/plugins/privacy/) \r\n 内置隐私插件(privacy plugin) 在 [9.5.0](https://github.com/squidfunk/mkdocs-material/releases/tag/9.5.0) 中已经k可以正常使用了,下一个值得期待的就是该插件的 [`assets_exclude`](https://squidfunk.github.io/mkdocs-material/plugins/privacy/#config.assets_exclude) 功能!', 'bodyText': 'MkDocs 是一个快速、简单、华丽的静态网站生成器,适用于构建项目文档。文档源文件以 Markdown 编写,并使用一个 YAML 文件来进行配置。Material for MkDocs 是 MkDocs 的一个主题配置,更加简洁美观,更新和维护也更加及时和频繁,且社区也更加活跃。\n\n安装\n主要使用的一些软件包以及模块 (requirements.txt) 如下:\nmkdocs==1.5.3\nmkdocs-material\nmkdocs-rss-plugin\nmkdocs-git-revision-date-plugin\nmkdocs-include-dir-to-nav==1.2.0\nmkdocs-glightbox\njieba\n\npip3 install -r requirements.txt\n\n查看 mkdocs-material, mkdocs 的版本:\n$ mkdocs --version\nmkdocs, version 1.5.3 from /usr/local/software/python-3.9.18/lib/python3.9/site-packages/mkdocs (Python 3.9)\n\n$ pip3 show mkdocs-material\nName: mkdocs-material\nVersion: 9.4.4\nSummary: Documentation that simply works\nHome-page: \nAuthor: \nAuthor-email: Martin Donath \nLicense: \nLocation: /usr/local/software/python-3.9.18/lib/python3.9/site-packages\nRequires: babel, colorama, jinja2, markdown, mkdocs, mkdocs-material-extensions, paginate, pygments, pymdown-extensions, regex, requests\nRequired-by:\n使用\n本地预览:\n$ mkdocs serve -a 0.0.0.0:8000\n\n问题与解决\n\nPagination 分页与 git-revision-date 冲突,导致无法构建 - 参考 mkdocs-material/discussions/6156\nSupport Markdown in the copyright string #5134\n如何在 MkDocs 的版权部分自动添加年份 - squidfunk/mkdocs-material#4969\n如何定制博客插件的归档页面 - squidfunk/mkdocs-material#6324\n\n期待的功能\n这是一个个人非常期待的功能,大部分目前已经可以在 Insiders 版本中使用,社区公开的版本尚无法使用。\n\n博客插件的自定义归档、目录页面每页文档数 - squidfunk/mkdocs-material#6383\n内置隐私插件(方便内网/国内部署加速访问)- Built-in privacy plugin - Material for MkDocs\n内置隐私插件(privacy plugin) 在 9.5.0 中已经k可以正常使用了,下一个值得期待的就是该插件的 assets_exclude 功能!', 'bodyHTML': '

MkDocs 是一个快速、简单、华丽的静态网站生成器,适用于构建项目文档。文档源文件以 Markdown 编写,并使用一个 YAML 文件来进行配置。Material for MkDocsMkDocs 的一个主题配置,更加简洁美观,更新和维护也更加及时和频繁,且社区也更加活跃。

\n\n

安装

\n

主要使用的一些软件包以及模块 (requirements.txt) 如下:

\n
mkdocs==1.5.3\nmkdocs-material\nmkdocs-rss-plugin\nmkdocs-git-revision-date-plugin\nmkdocs-include-dir-to-nav==1.2.0\nmkdocs-glightbox\njieba\n
\n
pip3 install -r requirements.txt\n
\n

查看 mkdocs-material, mkdocs 的版本:

\n
$ mkdocs --version\nmkdocs, version 1.5.3 from /usr/local/software/python-3.9.18/lib/python3.9/site-packages/mkdocs (Python 3.9)\n\n$ pip3 show mkdocs-material\nName: mkdocs-material\nVersion: 9.4.4\nSummary: Documentation that simply works\nHome-page: \nAuthor: \nAuthor-email: Martin Donath <martin.donath@squidfunk.com>\nLicense: \nLocation: /usr/local/software/python-3.9.18/lib/python3.9/site-packages\nRequires: babel, colorama, jinja2, markdown, mkdocs, mkdocs-material-extensions, paginate, pygments, pymdown-extensions, regex, requests\nRequired-by:
\n

使用

\n

本地预览:

\n
$ mkdocs serve -a 0.0.0.0:8000\n
\n

问题与解决

\n
    \n
  1. Pagination 分页与 git-revision-date 冲突,导致无法构建 - 参考 mkdocs-material/discussions/6156
  2. \n
  3. Support Markdown in the copyright string #5134
  4. \n
  5. 如何在 MkDocs 的版权部分自动添加年份 - squidfunk/mkdocs-material#4969
  6. \n
  7. 如何定制博客插件的归档页面 - squidfunk/mkdocs-material#6324
  8. \n
\n

期待的功能

\n

这是一个个人非常期待的功能,大部分目前已经可以在 Insiders 版本中使用,社区公开的版本尚无法使用。

\n', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '为 Material for MkDocs 增加博客插件', 'number': 36, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/36', 'createdAt': '2023-12-06T01:26:26Z', 'lastEditedAt': None, 'updatedAt': '2024-01-04T05:43:47Z', 'body': 'Material for MkDocs 从 9.2.0 开始内置博客插件,内置博客插件添加了对从帖子文件夹构建博客的支持,这些帖子带有日期和其他结构化数据注释。\r\n\r\n\r\n\r\nMaterial for MkDocs makes it very easy to build a blog, either as a sidecar to your documentation or standalone. Focus on your content while the engine does all the heavy lifting, automatically generating archive and category indexes, post slugs, configurable pagination and more.\r\n\r\nMaterial for MkDocs 使构建博客变得非常容易,无论是作为文档的附属工具还是独立的博客。专注于您的内容,而引擎会完成所有繁重的工作,自动生成存档和类别索引、帖子段、可配置的分页等等。\r\n\r\n存在的一些问题和使用体验:\r\n\r\n1. 在 Markdown 中使用 `` 的写法分割 description 和全文,总感觉有点别扭;\r\n2. Pagination 分页与 `git-revision-date` 冲突,会引发构建错误 - 参考 [mkdocs-material/discussions#6156](https://github.com/squidfunk/mkdocs-material/discussions/6156)\r\n\r\n## 写博客\r\n\r\n有感于 Material for MkDocs 的博客结构,现在基本上可以实现使用 Discussions 进行 MkDocs blog 编辑与写作 —— 在 Discussions 上写完文章,借助第三方工具或者 GitHub Actions 导出为 Markdown 文件,保存到 `docs/blog/posts` 就可以啦!\r\n\r\n## 加评论\r\n\r\n借助 [giscus](https://giscus.app/zh-CN),可以非常方便在文章页中插入指定的 discussions —— 在导出 discussions 的时候,在文章尾部增加类似以下 JavaScript 即可:\r\n```javascript\r\n\r\n```\r\n\r\n## 自定义归档页面\r\n\r\n[mkdocs-material](https://github.com/squidfunk/mkdocs-material) 的归档页面跟博客 index 主页面基本是一个样,如果想要列表式的自定义,可以参考 [squidfunk/mkdocs-material#6324](https://github.com/squidfunk/mkdocs-material/discussions/6324) 和 [squidfunk/mkdocs-material#6383](https://github.com/squidfunk/mkdocs-material/issues/6383)。\r\n\r\n官方在 [8ecee7b](https://github.com/squidfunk/mkdocs-material-insiders/commit/8ecee7b9dbdc5b2a0befd043a048ad25d56c784f) (Insiders) 中增加了几个个性化的新设置参数: \r\n \r\n- [`archive_pagination`](https://squidfunk.github.io/mkdocs-material/plugins/blog/#config.archive_pagination)\r\n- [`archive_pagination_per_page`](https://squidfunk.github.io/mkdocs-material/plugins/blog/#config.archive_pagination_per_page)\r\n- [`categories_pagination`](https://squidfunk.github.io/mkdocs-material/plugins/blog/#config.categories_pagination)\r\n- [`categories_pagination_per_page`](https://squidfunk.github.io/mkdocs-material/plugins/blog/#config.categories_pagination_per_page)\r\n\r\n所以,等开放给公用版本使用后,可以再好好折腾一下。\r\n', 'bodyText': 'Material for MkDocs 从 9.2.0 开始内置博客插件,内置博客插件添加了对从帖子文件夹构建博客的支持,这些帖子带有日期和其他结构化数据注释。\n\nMaterial for MkDocs makes it very easy to build a blog, either as a sidecar to your documentation or standalone. Focus on your content while the engine does all the heavy lifting, automatically generating archive and category indexes, post slugs, configurable pagination and more.\nMaterial for MkDocs 使构建博客变得非常容易,无论是作为文档的附属工具还是独立的博客。专注于您的内容,而引擎会完成所有繁重的工作,自动生成存档和类别索引、帖子段、可配置的分页等等。\n存在的一些问题和使用体验:\n\n在 Markdown 中使用 的写法分割 description 和全文,总感觉有点别扭;\nPagination 分页与 git-revision-date 冲突,会引发构建错误 - 参考 mkdocs-material/discussions#6156\n\n写博客\n有感于 Material for MkDocs 的博客结构,现在基本上可以实现使用 Discussions 进行 MkDocs blog 编辑与写作 —— 在 Discussions 上写完文章,借助第三方工具或者 GitHub Actions 导出为 Markdown 文件,保存到 docs/blog/posts 就可以啦!\n加评论\n借助 giscus,可以非常方便在文章页中插入指定的 discussions —— 在导出 discussions 的时候,在文章尾部增加类似以下 JavaScript 即可:\n\n自定义归档页面\nmkdocs-material 的归档页面跟博客 index 主页面基本是一个样,如果想要列表式的自定义,可以参考 squidfunk/mkdocs-material#6324 和 squidfunk/mkdocs-material#6383。\n官方在 8ecee7b (Insiders) 中增加了几个个性化的新设置参数:\n\narchive_pagination\narchive_pagination_per_page\ncategories_pagination\ncategories_pagination_per_page\n\n所以,等开放给公用版本使用后,可以再好好折腾一下。', 'bodyHTML': '

Material for MkDocs 从 9.2.0 开始内置博客插件,内置博客插件添加了对从帖子文件夹构建博客的支持,这些帖子带有日期和其他结构化数据注释。

\n\n

Material for MkDocs makes it very easy to build a blog, either as a sidecar to your documentation or standalone. Focus on your content while the engine does all the heavy lifting, automatically generating archive and category indexes, post slugs, configurable pagination and more.

\n

Material for MkDocs 使构建博客变得非常容易,无论是作为文档的附属工具还是独立的博客。专注于您的内容,而引擎会完成所有繁重的工作,自动生成存档和类别索引、帖子段、可配置的分页等等。

\n

存在的一些问题和使用体验:

\n
    \n
  1. 在 Markdown 中使用 <!-- more --> 的写法分割 description 和全文,总感觉有点别扭;
  2. \n
  3. Pagination 分页与 git-revision-date 冲突,会引发构建错误 - 参考 mkdocs-material/discussions#6156
  4. \n
\n

写博客

\n

有感于 Material for MkDocs 的博客结构,现在基本上可以实现使用 Discussions 进行 MkDocs blog 编辑与写作 —— 在 Discussions 上写完文章,借助第三方工具或者 GitHub Actions 导出为 Markdown 文件,保存到 docs/blog/posts 就可以啦!

\n

加评论

\n

借助 giscus,可以非常方便在文章页中插入指定的 discussions —— 在导出 discussions 的时候,在文章尾部增加类似以下 JavaScript 即可:

\n
<script src="https://giscus.app/client.js"\n        data-repo="shenweiyan/Knowledge-Garden"\n        data-repo-id="R_kgDOKgxWlg"\n        data-mapping="number"\n        data-term="4"\n        data-reactions-enabled="1"\n        data-emit-metadata="0"\n        data-input-position="bottom"\n        data-theme="light"\n        data-lang="zh-CN"\n        crossorigin="anonymous"\n        async>\n</script>
\n

自定义归档页面

\n

mkdocs-material 的归档页面跟博客 index 主页面基本是一个样,如果想要列表式的自定义,可以参考 squidfunk/mkdocs-material#6324squidfunk/mkdocs-material#6383

\n

官方在 8ecee7b (Insiders) 中增加了几个个性化的新设置参数:

\n\n

所以,等开放给公用版本使用后,可以再好好折腾一下。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '备用讨论', 'number': 35, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/35', 'createdAt': '2023-12-06T01:22:49Z', 'lastEditedAt': '2024-03-21T03:19:44Z', 'updatedAt': '2024-03-21T03:19:46Z', 'body': '备用讨论', 'bodyText': '备用讨论', 'bodyHTML': '

备用讨论

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '0.1-站点'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '博客与写作的一些思考', 'number': 34, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/34', 'createdAt': '2023-12-05T06:32:32Z', 'lastEditedAt': '2023-12-08T05:32:46Z', 'updatedAt': '2023-12-11T08:30:56Z', 'body': '关于写作原本的想法,只是想写点自己在学习、工作、生活上的一些心得和体会,把一些知识点记录下来。\r\n\r\n留言的初衷是,希望自己写下来的东西能够有人一起探讨。哪怕你把我的观点批评得一无是处也可以,哪怕你说我的句子狗屁不通也没关系,只要有评判,我相信总有一天我会变得更好。\r\n\r\n\r\n\r\n写作也好留言也罢,博客也只是一种实现的载体,语雀、博客园也是同样的道理,平台的选择虽然重要,但根本还是在于内容。\r\n\r\n每次看到人家一些内容翔实,界面优雅的博客,总要跟自己说,要忍住再去折腾博客的冲动,什么 UI,什么 CSS/HTML,都是浮云,内容才是核心,老老实实回归最简单的 Issues 和 Discussions 已经足够了。另外,需要知道的是,博客其实就是写给自己看的,什么 SEO 流量、关注度、知名度还是需要一颗随缘的心态。\r\n\r\n使用 Issues 当作博客也是挺不错的~\r\n\r\n- \r\n- \r\n- \r\n\r\n关于部分平台商业化的写作,有两点自认为讲的挺好: \r\n\r\n- 商业化已经改变了写作的初衷。 \r\n- 当写文章变成盈利的手段,那么,写出来的东西是没有灵魂的。', 'bodyText': '关于写作原本的想法,只是想写点自己在学习、工作、生活上的一些心得和体会,把一些知识点记录下来。\n留言的初衷是,希望自己写下来的东西能够有人一起探讨。哪怕你把我的观点批评得一无是处也可以,哪怕你说我的句子狗屁不通也没关系,只要有评判,我相信总有一天我会变得更好。\n\n写作也好留言也罢,博客也只是一种实现的载体,语雀、博客园也是同样的道理,平台的选择虽然重要,但根本还是在于内容。\n每次看到人家一些内容翔实,界面优雅的博客,总要跟自己说,要忍住再去折腾博客的冲动,什么 UI,什么 CSS/HTML,都是浮云,内容才是核心,老老实实回归最简单的 Issues 和 Discussions 已经足够了。另外,需要知道的是,博客其实就是写给自己看的,什么 SEO 流量、关注度、知名度还是需要一颗随缘的心态。\n使用 Issues 当作博客也是挺不错的~\n\nhttps://github.com/Meekdai/Gmeek\nhttps://github.com/yihong0618/gitblog\nhttps://github.com/yutingzhao1991/github-blogs-collector\n\n关于部分平台商业化的写作,有两点自认为讲的挺好:\n\n商业化已经改变了写作的初衷。\n当写文章变成盈利的手段,那么,写出来的东西是没有灵魂的。', 'bodyHTML': '

关于写作原本的想法,只是想写点自己在学习、工作、生活上的一些心得和体会,把一些知识点记录下来。

\n

留言的初衷是,希望自己写下来的东西能够有人一起探讨。哪怕你把我的观点批评得一无是处也可以,哪怕你说我的句子狗屁不通也没关系,只要有评判,我相信总有一天我会变得更好。

\n\n

写作也好留言也罢,博客也只是一种实现的载体,语雀、博客园也是同样的道理,平台的选择虽然重要,但根本还是在于内容。

\n

每次看到人家一些内容翔实,界面优雅的博客,总要跟自己说,要忍住再去折腾博客的冲动,什么 UI,什么 CSS/HTML,都是浮云,内容才是核心,老老实实回归最简单的 Issues 和 Discussions 已经足够了。另外,需要知道的是,博客其实就是写给自己看的,什么 SEO 流量、关注度、知名度还是需要一颗随缘的心态。

\n

使用 Issues 当作博客也是挺不错的~

\n\n

关于部分平台商业化的写作,有两点自认为讲的挺好:

\n
    \n
  • 商业化已经改变了写作的初衷。
  • \n
  • 当写文章变成盈利的手段,那么,写出来的东西是没有灵魂的。
  • \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': [{'name': '博客'}]}, 'comments': {'nodes': [{'body': '自娱自乐的小树洞,我也是', 'author': {'login': 'obaby'}}]}}, {'title': '使用 meta 实现页面的定时刷新或跳转', 'number': 33, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/33', 'createdAt': '2023-12-05T03:25:01Z', 'lastEditedAt': '2024-02-29T01:26:02Z', 'updatedAt': '2024-02-29T01:26:02Z', 'body': '这个方法最开始是在 [Linlin Yan (颜林林)](https://github.com/yanlinlin82) 的 GitHub Pages 上第一次看到。后来,随着自己也用上了,就开始有了更深一些的认识。\r\n\r\n\r\n\r\n## 跳转域名\r\n\r\n在 [yanlinlin82/yanlinlin82.github.io](https://github.com/yanlinlin82/yanlinlin82.github.io/tree/master) 看到一个通过 可以直接重定向到 的用法 —— 只需要把 `index.html` 写成这样就可以:\r\n```html\r\n\r\n\r\n \r\n \r\n\r\n```\r\n\r\n## 页面定时跳转与刷新\r\n\r\n这部分的内容主要来源自:《[小tip: 使用meta实现页面的定时刷新或跳转](https://www.zhangxinxu.com/wordpress/2015/03/meta-http-equiv-refresh-content/)》。\r\n\r\n> ### meta 源信息功能之页面定时跳转与刷新\r\n> \r\n> 几乎所有的网页头部都有``源信息。除了我们常用的定义编码、关键字(name=”keywords”)、描述(name=”description”)(for SEO),还可以定义视区大小、缩放比例等(for 移动端),如下:\r\n> \r\n> ```\r\n> \r\n> ```\r\n> \r\n> 以及,定义网页的过期时间,Cookie 的过期时间等等。\r\n> \r\n> 文本要介绍的内容,科科,跟上面都没关系。哦,抱歉,都有关系,只是名称我故意没提到。主角嘛,总要最后闪亮登场!\r\n> \r\n> 就是我们网页平时跳转,还可以使用 `` 实现,下面几个典型代码示例: \r\n> ```html \r\n> \r\n> ```\r\n> 这个表示当前页面每5秒钟刷一下,刷一下~\r\n> \r\n> ```html\r\n> \r\n> ```\r\n> 这个表示当前页面2秒后跳到首页~ \r\n> \r\n> ```html\r\n> \r\n> ```\r\n> 页面直接跳转到腾讯网~\r\n> \r\n> 所以,当我们下次遇到“登录成功,正在跳转到您之前访问页面……”的时候,可以使用``的这个`refresh`刷新,跳转功能,可以说是成本最低的。 \r\n> \r\n> 您可以狠狠地点击这里:[meta与当前页面定时刷新Demo](http://www.zhangxinxu.com/study/201503/meta-fresh-content.html) \r\n> ![meta-refresh](https://shub.weiyan.tech/kgarden/2024/01/meta-refresh.37epe9yaam80.png)\r\n> \r\n> 上面 Demo 效果就是上面第1个示例代码效果。 \r\n> \r\n> 根据我的测试,此特性包括IE7在内的浏览器都是支持的。 \r\n> \r\n> ### 问题来了:为何 meta 跳转不火呢?\r\n> \r\n> 大家可以看到,`meta` 跳转,使用方便,不用写 JS,不用会后台代码,定时跳转刷新什么的玩得照样很溜,而且兼容性好,为啥总感觉不温不火,很少看见有人提及呢? \r\n> \r\n> 新晋的小伙伴不知有没有听过这么一个词,叫做“万恶的IE6年代”。\r\n> \r\n> 据说,当年,这一批老旧的浏览器,问题很多,其中就有对`meta` 两个小小的不友好。我也是听说,不一定准确。坊间是这么传闻的: \r\n> \r\n> - 时间设为0的跳转,有时候页面会闪一下; \r\n> - 跳转到其他页面,浏览器后退按钮是不能用的; \r\n> \r\n> 但是啊,现在是什么年代啊,监狱风云都拍到第二季了,这些老问题,我觉得就可以忽略不计了。 \r\n> \r\n> 不妨大胆试试 `meta` 跳转,好好利用下浏览器的原生特性,说不定就会发现比什么 JS 跳转之流用得更开心。\r\n\r\n所以,在文章的最后有一个小想法 —— 我们是不是也可以利用这个方法实现无数个链接 301 重定向( URL 转发),再也不需要担心是否需要主机+Nginx 之类!\r\n', 'bodyText': '这个方法最开始是在 Linlin Yan (颜林林) 的 GitHub Pages 上第一次看到。后来,随着自己也用上了,就开始有了更深一些的认识。\n\n跳转域名\n在 yanlinlin82/yanlinlin82.github.io 看到一个通过 https://yanlinlin82.github.io 可以直接重定向到 https://yanlinlin.cn/ 的用法 —— 只需要把 index.html 写成这样就可以:\n\n\n \n \n\n页面定时跳转与刷新\n这部分的内容主要来源自:《小tip: 使用meta实现页面的定时刷新或跳转》。\n\nmeta 源信息功能之页面定时跳转与刷新\n几乎所有的网页头部都有源信息。除了我们常用的定义编码、关键字(name=”keywords”)、描述(name=”description”)(for SEO),还可以定义视区大小、缩放比例等(for 移动端),如下:\n\n\n以及,定义网页的过期时间,Cookie 的过期时间等等。\n文本要介绍的内容,科科,跟上面都没关系。哦,抱歉,都有关系,只是名称我故意没提到。主角嘛,总要最后闪亮登场!\n就是我们网页平时跳转,还可以使用 实现,下面几个典型代码示例:\n\n这个表示当前页面每5秒钟刷一下,刷一下~\n\n这个表示当前页面2秒后跳到首页~\n\n页面直接跳转到腾讯网~\n所以,当我们下次遇到“登录成功,正在跳转到您之前访问页面……”的时候,可以使用的这个refresh刷新,跳转功能,可以说是成本最低的。\n您可以狠狠地点击这里:meta与当前页面定时刷新Demo\n\n上面 Demo 效果就是上面第1个示例代码效果。\n根据我的测试,此特性包括IE7在内的浏览器都是支持的。\n问题来了:为何 meta 跳转不火呢?\n大家可以看到,meta 跳转,使用方便,不用写 JS,不用会后台代码,定时跳转刷新什么的玩得照样很溜,而且兼容性好,为啥总感觉不温不火,很少看见有人提及呢?\n新晋的小伙伴不知有没有听过这么一个词,叫做“万恶的IE6年代”。\n据说,当年,这一批老旧的浏览器,问题很多,其中就有对meta 两个小小的不友好。我也是听说,不一定准确。坊间是这么传闻的:\n\n时间设为0的跳转,有时候页面会闪一下;\n跳转到其他页面,浏览器后退按钮是不能用的;\n\n但是啊,现在是什么年代啊,监狱风云都拍到第二季了,这些老问题,我觉得就可以忽略不计了。\n不妨大胆试试 meta 跳转,好好利用下浏览器的原生特性,说不定就会发现比什么 JS 跳转之流用得更开心。\n\n所以,在文章的最后有一个小想法 —— 我们是不是也可以利用这个方法实现无数个链接 301 重定向( URL 转发),再也不需要担心是否需要主机+Nginx 之类!', 'bodyHTML': '

这个方法最开始是在 Linlin Yan (颜林林) 的 GitHub Pages 上第一次看到。后来,随着自己也用上了,就开始有了更深一些的认识。

\n\n

跳转域名

\n

yanlinlin82/yanlinlin82.github.io 看到一个通过 https://yanlinlin82.github.io 可以直接重定向到 https://yanlinlin.cn/ 的用法 —— 只需要把 index.html 写成这样就可以:

\n
<!DOCTYPE html>\n<html>\n  <head><meta http-equiv="refresh" content="0; url=https://yanlinlin.cn/"></head>\n  <body></body>\n</html>
\n

页面定时跳转与刷新

\n

这部分的内容主要来源自:《小tip: 使用meta实现页面的定时刷新或跳转》。

\n
\n

meta 源信息功能之页面定时跳转与刷新

\n

几乎所有的网页头部都有<meta>源信息。除了我们常用的定义编码、关键字(name=”keywords”)、描述(name=”description”)(for SEO),还可以定义视区大小、缩放比例等(for 移动端),如下:

\n
<meta name="viewport" content="width=device-width,initial-scale=1.0">\n
\n

以及,定义网页的过期时间,Cookie 的过期时间等等。

\n

文本要介绍的内容,科科,跟上面都没关系。哦,抱歉,都有关系,只是名称我故意没提到。主角嘛,总要最后闪亮登场!

\n

就是我们网页平时跳转,还可以使用 <meta> 实现,下面几个典型代码示例:

\n
<meta http-equiv="refresh" content="5">
\n

这个表示当前页面每5秒钟刷一下,刷一下~

\n
<meta http-equiv="refresh" content="2; url=\'/\'">
\n

这个表示当前页面2秒后跳到首页~

\n
<meta http-equiv="refresh" content="0; url=\'http://www.qq.com/\'">
\n

页面直接跳转到腾讯网~

\n

所以,当我们下次遇到“登录成功,正在跳转到您之前访问页面……”的时候,可以使用<meta>的这个refresh刷新,跳转功能,可以说是成本最低的。

\n

您可以狠狠地点击这里:meta与当前页面定时刷新Demo
\nmeta-refresh

\n

上面 Demo 效果就是上面第1个示例代码效果。

\n

根据我的测试,此特性包括IE7在内的浏览器都是支持的。

\n

问题来了:为何 meta 跳转不火呢?

\n

大家可以看到,meta 跳转,使用方便,不用写 JS,不用会后台代码,定时跳转刷新什么的玩得照样很溜,而且兼容性好,为啥总感觉不温不火,很少看见有人提及呢?

\n

新晋的小伙伴不知有没有听过这么一个词,叫做“万恶的IE6年代”。

\n

据说,当年,这一批老旧的浏览器,问题很多,其中就有对meta 两个小小的不友好。我也是听说,不一定准确。坊间是这么传闻的:

\n
    \n
  • 时间设为0的跳转,有时候页面会闪一下;
  • \n
  • 跳转到其他页面,浏览器后退按钮是不能用的;
  • \n
\n

但是啊,现在是什么年代啊,监狱风云都拍到第二季了,这些老问题,我觉得就可以忽略不计了。

\n

不妨大胆试试 meta 跳转,好好利用下浏览器的原生特性,说不定就会发现比什么 JS 跳转之流用得更开心。

\n
\n

所以,在文章的最后有一个小想法 —— 我们是不是也可以利用这个方法实现无数个链接 301 重定向( URL 转发),再也不需要担心是否需要主机+Nginx 之类!

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': [{'name': '公众号'}]}, 'comments': {'nodes': []}}, {'title': '2022 年的十大生物学突破', 'number': 32, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/32', 'createdAt': '2023-12-01T03:39:00Z', 'lastEditedAt': None, 'updatedAt': '2024-01-04T05:45:16Z', 'body': '> **作者 |** [Niko McCarty](https://substack.com/profile/11154869-niko-mccarty) \r\n> **翻译 |** [章鱼猫先生](https://www.yuque.com/shenweiyan) \r\n> **日期 |** 原文发表于 2022.12.10 \r\n> **来源 |** [Biology Breakthroughs of 2022](https://cell.substack.com/p/biology-breakthroughs-2022) - Codon \r\n\r\n> 您正在阅读 Codon,这是一份关于生物 + 技术进步和为人类创造更光明未来的想法的时事通讯。 \r\n> 这是今年的最后一部作品。几周后我会在这里见到你! \r\n\r\n\r\n\r\n

\r\n
\r\n 大约 1950 年代,戴着加压氧气面罩的男子\r\n

\r\n\r\n> "当你经历历史时,历史永远不会像历史。它总是看起来很混乱和凌乱,而且总是让人感觉不舒服。" \r\n> —— 约翰·W·加德纳\r\n\r\n许多我非常敬佩的作家都对“进步的停滞”写出了令人信服的论战。科学越来越难,发现越来越小(平均而言),这两件事都很糟糕。\r\n\r\n如果你召集来自世界顶级院系的 93 位物理学家,让他们将 1910 年代获得诺贝尔奖的发现与 80 年代的另一个发现进行比较,他们通常会说更早的发现更重要。\r\n\r\n与五十年前相比,今天实现技术飞跃也更加困难。将计算机芯片上的晶体管数量增加一倍(又名摩尔定律)需要的研究人员数量是 1970 年代初期的 [18 倍](https://www.aeaweb.org/articles?id=10.1257/aer.20180338)。今天发表的学术论文被美国专利引用的可能性不到 30 年前发表的论文的[一半](https://mattsclancy.substack.com/p/science-is-getting-harder)。\r\n\r\n这些不断缩减的回报正处于历史高位之中。\r\n\r\n美国每年授予超过 50,000 个科学和工程博士学位;这个数字在 1960 年还不到 10,000。联邦对科学的资助也(基本上)处于历史最高水平。科学论文的总数呈指数级增长,但每篇论文的平均作者人数在过去一百年里大约翻了两番。\r\n

\r\n
\r\n From "The Science of Science" by Wang and Barabási.\r\n

\r\n\r\n出于某种原因,这些都是生物学进步的不完美指标。但是有很多零散的证据表明,科学正在变得越来越不划算,即使感觉进步从未像现在这样快。我相信——基于轶事证据,真的——如果以每年获得诺贝尔奖的发现为基准,生物技术不会停滞不前。只是诺贝尔奖每年都会颁发一次,而且不乏令人惊叹的论文在排队等待获得最高奖项。所以,当然,并不是每个有价值的人都会赢。\r\n\r\n哦,如果你拿我之前提到的物理学调查结果,对医学和化学做同样的实验,结果就会颠倒过来——20 世纪下半叶发现的相对重要性超过了上半叶。\r\n\r\n不管停滞与否,生物学都存在巨大的低效率。它可以——应该!- 移动得更快。\r\n\r\n许多论文需要一年多的时间才能发表,在期刊官僚的严密监视下,被搁置在数字化的边缘。漫长的等待可能也不值得——同行评审通常是无用的,而且很多糟糕的科学无论如何都能通过。许多伟大的想法也从来没有发表在论文上,因为,好吧,他们从来没有得到资助。NIH 拨款审查非常不一致。如果您向 43 位不同的审稿人提供 25 份拨款建议,他们的评定者间可靠性(衡量分数一致性的指标)基本上为零,即使拨款已经获得资金和先前评审小组的高分!给予相同审稿人的无资金资助与有资金资助的资助得分一样。\r\n\r\n那么生物学文献呢?那也是一团糟。山姆·罗德里克斯 ([Sam Rodriques](https://www.sam-rodriques.com/post/why-is-progress-in-biology-so-slow)) 在最近的一篇文章中写道,科学论文“因委托而变得不可靠”,并且“因遗漏而变得不可靠”。换句话说,一些研究(一小部分)只是编造的。教授或学生为了发表论文而捏造数字,如果有人说他们在胡说八道,编辑可能要过[好几年](https://newscience.substack.com/p/laws-of-science)才会撤稿。\r\n\r\n不过,更大的问题可能是疏忽。科学期刊喜欢发表积极的结果,所以大多数消极的发现永远不会出现在光鲜的期刊上。如果有人进行的实验表明药物 A 与受体 B 结合,他们会发表它——但忽略提及药物 A 不会通过 Z 与受体 C 结合。无效结果很少传给科学家,他们中的许多人已经几个月来一次又一次尝试实验的痛苦经历,后来才发现 1970 年代的一篇不起眼的论文使他们所有的努力都变得毫无意义。\r\n\r\n我告诉你这些悲伤的事情——停滞不前的科学和可怕的低效率的故事——是为了说明一个观点:**生物学在去年取得了如此大的进步,真是令人惊讶**。生物学的进步证明了人类渴望探索、失败,然后继续前进的愿望。这份时事通讯庆祝人类的成就,并重点介绍了过去 12 个月**生物学领域的十大进步**。\r\n\r\n此列表中的所有内容均来自 Codon 的上一期,因此希望您能在评论中指出我的错误和遗漏。我的入选标准很简单:该列表仅包括 2022 年期间发布到 bioRxiv 或发表在期刊上的论文。我不包括公司成就——这实际上可能是它自己的列表——除非他们发布了数据。(入选)列表中的一些项目包括了多篇论文,因为整个子领域发展得非常快。\r\n\r\n汇总“十佳排名”最大的危险是完全主观的,有很多优秀的东西没有入选,而且很多其他作家已经做到了(虽然我还没有看到专门针对生物学的清单)。诺亚·史密斯 (Noah Smith) 发布了他 2023 年的技术乐观主义清单 ([techno-optimism list](https://noahpinion.substack.com/p/techno-optimism-for-2023)),其中包括对生物技术的简要提及,而《大西洋月刊》(The Atlantic) 发表了他们的 "年度突破 ([breakthroughs of the year](https://www.theatlantic.com/newsletters/archive/2022/12/technology-medicine-law-ai-10-breakthroughs-2022/672390/))",然后立即将该文章设置为付费文章。\r\n\r\n然而,有必要专门为生物学列出一份完整的榜单,因为很多伟大的事情在人工智能的阴影下被忽略了。人类基因组计划(始于 1990 年)终于在[今年完成了](https://www.science.org/toc/science/376/6588),一个庞大的科学家团队填补了最后 8% 的序列空白。科学家们还使用 mirror-image DNA 聚合酶制作了镜像 DNA ([mirror-image DNA](https://www.nature.com/articles/s41587-022-01337-8)),并发现了一类新的 CRISPR 蛋白质,它们可以[剪切蛋白质](https://cell.substack.com/p/crispr-can-cut-proteins-too-index)而不是基因。机器学习正在蛋白质工程中掀起波澜,例如有一种基于算法被设计出来的酶,这种酶可以比自然界中发现的任何酶更快地[分解 PET 塑料](https://cell.substack.com/p/ai-designed-enzyme-eats-plastic)。\r\n\r\n我不确定今年的进展是否与生物进展是否整体停滞不前有关。但有一件事是不变的:生物学变得越来越奇怪,而我会一直关注它。\r\n\r\n### 10. 走向合成细胞\r\n\r\n从纯化学成分构建合成细胞是生物学的圣杯。如果实现了这一壮举,将证明我们已足够详细地理解生命运作的大体轮廓,并有足够的细节可以在实验室中重现它。这也将成为定制细胞的起点,这些细胞可以检测有毒污染或制造药物,同时又不会成为生物安全风险或存在感染风险。\r\n\r\n今年有几篇论文推动了合成细胞的发展,但其中有两篇让人印象深刻。第一篇是在 bioRxiv 上发表的预印本,据称是**首次证明核糖体**(大分子蛋白质,负责合成其他蛋白质)**可以在活细胞之外制造**。这是在合成细胞内从头生产蛋白质的重要起点。\r\n\r\n我们还在合成细胞分裂方面取得了重要进展。一项研究报告说,仅使用五种蛋白质就可以在脂肪泡中制造合成分裂环!当这些蛋白质聚集在一起时,它们会收缩并向气泡施加力(下面的 GIF)。 \r\n

\r\n
\r\n 合成分裂环在气泡内形成的延时摄影\r\n

\r\n\r\n### 9. 更好的碱基编辑器\r\n\r\n早在 2016 年,《自然》杂志的一篇论文就报道了第一个碱基编辑蛋白,它可以将 DNA 中的 "C" 替换为 "T",而无需将基因组一分为二。它的重要性立即显而易见——许多严重的遗传疾病是由 DNA 中的单个碱基交换引起的,现在这些突变可以被修复。\r\n\r\n碱基编辑器已经成熟。这些基因编辑蛋白在发明后仅仅五年就以创纪录的速度进入临床试验,目前 Verve、Beam 和其他公司正在进行针对镰状细胞病、高胆固醇和 Stargardt 病的[试验](https://www.nature.com/articles/d41573-022-00124-z)。\r\n\r\n然而,碱基编辑的主要挑战之一是编辑线粒体基因组很棘手,[许多遗传疾病](https://www.chop.edu/conditions-diseases/mitochondrial-dna-common-mutation-syndromes)都源于此。早在 2020 年,[一篇论文](https://www.nature.com/articles/s41586-020-2477-4)就表明碱基编辑器可以成功进入线粒体并使 "C" 变为 "T",但其前景并不乐观。今年 5 月,[一篇后续论文](https://www.nature.com/articles/s41586-022-04836-5)称,实际上,这些线粒体基因编辑器诱发了 "大量" 脱靶突变,这意味着它们编辑的位置比预期的要多,弊大于利。\r\n\r\n但创新不会因失败而受阻。仅今年一年就至少发表了**三篇论文**,使线粒体碱基编辑器变得[更小](https://www.nature.com/articles/s41467-022-34784-7)或[更准确](https://doi.org/10.1016/j.cell.2022.03.039)。让碱基编辑酶进入线粒体或编辑其 DNA 从未如此简单。我相信我们很快就会看到一些针对线粒体相关疾病的临床试验。\r\n\r\n### 8. 噬菌体传播病毒\r\n\r\n今年对噬菌体来说是个好年头。这真的很合适,因为它也是 Felix d\'Herelle 著名实验 **100 周年纪念日**。1922 年,这位巴黎微生物学家证明噬菌体(感染细菌的小病毒)[可以根除](https://jamanetwork.com/journals/jamapediatrics/article-abstract/1173780)兔子和小动物体内的 "痢疾杆菌和其他杆菌"。\r\n\r\n我们现在正经历着临床疗法的准复兴时期,噬菌体经常被用来消除抗生素无效的感染(尤其是在欧洲医院)。几周前,一个欧洲科学家团队使用实验性噬菌体疗法[挽救了一名幼儿的生命](https://www.nature.com/articles/s41467-022-33294-w)。器官移植后,这个小男孩感染了抗生素无法清除的耐药性感染。在用定制的噬菌体鸡尾酒 (a custom-made phage cocktail) 治疗两年多后,孩子在家中恢复了健康。\r\n\r\n5 月,丹佛的一个团队使用噬菌体治疗一名患有严重囊性纤维化的男孩的脓肿分枝杆菌感染。噬菌体将感染控制了一年多,直到获得供体肺。我相信我们会在 2023 年看到定制噬菌体疗法进入临床。 \r\n

\r\n
\r\n

\r\n\r\n\r\n### 7. 血友病基因疗法\r\n\r\n[Hemgenix](https://www.fda.gov/vaccines-blood-biologics/vaccines/hemgenix) 是一种治疗 B 型血友病的基因疗法,几个月前获得了 FDA 的批准。它的价格达到了 350 万美元,使其成为有史以来最昂贵的药物(这并不好)。根据 III 期临床试验数据,它在患者的是安全有效期[至少两年](https://hemophilianewstoday.com/news/hemgenix-gene-therapy-benefits-sustained-2-years-phase-3-hope-b/)。\r\n\r\n血友病 A 的基因治疗进展缓慢,该病由一种名为 VIII 的不同凝血蛋白突变引起。5 月的一项研究表明,针对肝脏的基因疗法在非人类灵长类动物中效果很好,可以导致 "总凝血因子 VIII 输出增加 10 倍以上"。3 月份发表的一项有 134 名参与者参与的 I/II 期临床试验表明,使用腺相关病毒进行的基因疗法,也用于肝脏,可减少血友病患者的出血事件。但是,它带来了很多副作用;每个试验参与者至少有一次不良事件。尽管如此,血友病仍是基因治疗的 "低悬" 目标之一,这些试验是其他正在进行中的目标的有用酸性测试。\r\n\r\n### 6. 合成胚胎\r\n\r\n今年,从老鼠身上采集的干细胞被用来制造 "类胚胎结构",其中包含工作的肠道、跳动的心脏和头脑的雏形,而不需要精子或卵子。\r\n\r\n以色列的 Jacob Hanna 团队发表了一篇最初的论文,于 8 月[在 Cell 上发表](https://doi.org/10.1016/j.cell.2022.07.028)。据《卫报》报道,这些作者后来成立了一家名为 Renewal Bio 的[公司](https://www.theguardian.com/science/2022/aug/03/scientists-create-worlds-first-synthetic-embryos),"旨在培养人类合成胚胎,为医疗条件提供组织和细胞"。剑桥大学和加州理工学院的一个团队也在 8 月 2 日发布了一份[预印本](https://doi.org/10.1101/2022.08.01.502371),表明这些 "合成胚胎"准确地概括了 "从胚胎第 5.5 天到第 8.5 天的发育事件,包括原肠胚形成、前后轴的形成、大脑,跳动的心脏结构,以及胚胎外组织(包括卵黄囊和绒毛膜)的发育。"\r\n\r\n合成胚胎——正确形成的概率只有 0.5% 左右——有几个潜在的用途。例如,这些结构可以用于研究器官在发育过程中的形成,也可用于在不使用真实胚胎的情况下测试药物。 \r\n

\r\n
\r\n Embryoids after six days. From Kasey Lau et al. on bioRxiv. Link\r\n

\r\n\r\n### 5. 细胞重编程\r\n\r\n今年的一大亮点:首次证明仅靠化学物质就能将人体细胞[重新编程为干细胞](https://www.nature.com/articles/s41586-022-04593-5)。这一突破需要十多年的时间,并需使用 11 种不同的化学物质,以及一到两个月的工作时间,所以仍需要一些微调。早在 2013 年,同一个小组就已使用这种方法实现了[小鼠细胞](https://www.science.org/doi/10.1126/science.1239278)的转化,但人类细胞的转化过程要困难得多。\r\n\r\n这也不是第一项重新编程人类细胞的研究。这一荣誉属于山中伸弥 (Shinya Yamanaka),他在 2006 年通过表达四种蛋白质(现在著名的 "Yamanaka 因子")对 iPS 细胞进行了重编程。在随后的几十年中,其他研究小组使用病毒或 mRNA 对细胞进行重编程。但这种仅使用化学物质的方法脱颖而出,因为它在体外使用简单,而且化学混合物可以通过静脉注射输送到体内——不需要基因编辑。该方法提供了一种相对简单的工具来生成可用于再生医学的人类多能干细胞。\r\n\r\n### 4. 植物更容易设计\r\n\r\n我们生活在人类世,这是人类历史上一个可怕的时刻,**人造材料的重量超过地球上所有的生物量**,而且重量每年都在继续增加一倍。 \r\n

\r\n
\r\n "Global human-made mass exceeds all living biomass," by Elhacham E et al. in Nature. Link\r\n

\r\n\r\n在我们现有的生物质中,据估计有 83% 由植物持有。如果我们想要走出这场行星垃圾场的困境,那么,那么我们可能不得不对植物进行工程改造:让它们捕获更多的碳,[增强它们的光合作用](https://cell.substack.com/p/hacking-photosynthesis),种植生产更多的食物,等等!\r\n\r\n幸运的是,做到这一点从未如此简单。几十年来,合成生物学家已经对细菌和哺乳动物细胞进行了改造,使其具有越来越复杂的遗传回路,即使植物在很大程度上被忽视了。今年,两项重要进展改变了平衡。\r\n\r\n先是基因编辑技术,如 CRISPR,现在已经过优化,可以在植物中更好地发挥作用。例如,Prime 编辑器是可以插入、删除或交换 DNA 的 "搜索和替换" 基因编辑器。与其他 Prime 编辑器相比,新的 Plant Prime Editor 在植物细胞中的效率提高了 [3.4 倍](https://www.nature.com/articles/s41587-022-01254-w),并被用于在实验室中迅速使水稻植物对除草剂产生耐受性。\r\n\r\n但更大的进步是:斯坦福大学的一个团队发布了[一个完整的基因工具包](https://www.science.org/doi/10.1126/science.abo4326),可以像我们对细菌进行编程一样对植物进行 "编程"。新工具包包括大量合成启动子和转录因子,可用于控制植物中的基因表达。这些遗传部分被用于构建能够在本塞姆氏烟草和拟南芥中进行布尔逻辑运算的基因回路。作者还建立了逻辑门,可以控制植物根部的基因表达水平,从而控制它们的侧向密度。\r\n\r\n

\r\n
\r\n A genetic circuit controls how many lateral roots shoot out from a plant’s roots. Lateral density increases from left to right, with a wildtype plant shown on the far right. From Brophy et al. on bioRxiv.\r\n

\r\n\r\n### 3. 走向负碳\r\n\r\n生物学的一个众所周知的困难部分是难以扩展(进行大规模的研究)。在试管中改造一个能将糖转化为抗癌药物的细胞是一回事,但在一个千升生物反应器中做同样的事却是完全不同的挑战。\r\n\r\n这就是像 [LanzaTech](https://lanzatech.com/) 这样的公司令人兴奋的原因。他们实际上已经在工业工厂扩大了生物学规模。他们有试点设施,将工厂的废碳回收成燃料和化学品。这些工厂每年可以生产数千亿加仑的燃料,并且已经达到相当于每年减少数千辆汽车上路的排放量。\r\n\r\n几个月前,来自 LanzaTech 和西北大学的科学家们达到了[另一个里程碑](https://www.nature.com/articles/s41587-021-01195-w):使用一种名为 Clostridium autoethanogenum 的工程自养生物,他们在具有负碳足迹的过程中以工业规模生产丙酮和异丙醇。 "与导致温室气体释放的传统生产过程不同,我们的过程可以固定碳," 他们在发表的论文中写道。这是大规模生物学向前迈出的一大步。经过改造的微生物可以在不拖累大气的情况下改善污染物并产生化学物质。\r\n\r\n### 2. 异种移植成为现实\r\n\r\n这将作为 "异种移植年" 载入人类史册。异种移植的历史可以追溯到 20 世纪 60 年代中期——法国外科医生勒内·库斯 (Renè Kuss) 将猪肾移植到人体中,结果很快被患者的身体排斥——异种移植一直是一个失败的领域。最著名的例子可能是 80 年代 Stephanie Beauclair 或 Baby Fae 的手术,她从狒狒那里接受了一颗心脏,但不久后就去世了。\r\n\r\n不过,在过去四十年里,我们在从猪身上提取心脏并将其植入人体方面做得更好,因为基因编辑技术正在改进。现在比以往任何时候都更容易在猪的细胞中找到所有导致我们的身体排斥该器官的有害蛋白质,并从基因组中[系统地消除](https://www.science.org/doi/10.1126/science.aad1191)这些蛋白质编码基因。但进步从来都不是没有陷阱的。\r\n\r\n今年 1 月 7 日,马里兰大学的一组外科医生将[一颗猪的心脏移植](https://www.technologyreview.com/2022/01/11/1043374/gene-edited-pigs-heart-transplant/)到 57 岁的老大卫贝内特体内,[两个月后](https://www.technologyreview.com/2022/05/04/1051725/xenotransplant-patient-died-received-heart-infected-with-pig-virus/)他去世了。\r\n\r\n5 月,两只猪的肾脏被移植到脑死亡患者体内,并进行了 54 小时的监测,这让沮丧过后变得乐观起来。两个肾脏都产生了尿液,活组织检查没有显示出任何器官排斥的迹象。\r\n\r\n心脏移植可能因为器官感染了猪病毒而失败,但肾移植研究的作者没有检测到这种病毒。猪肾可能很快就会进入人们的生活。\r\n\r\n### 1. 我们离终结疟疾从未如此近\r\n\r\n如果您相信约翰·惠特菲尔德 (John Whitfield) 2002 年在《[自然](https://www.nature.com/articles/news021001-6)》杂志发表的这篇文章(该说法未被引用),"疟疾已经杀死了所有曾经生活过的人的一半"。即使该说法是错误的,在整个人类历史上,蚊子也已经集体杀死了数十亿人。昆虫混蛋干掉了亚历山大大帝、哥特人阿拉里克和但丁。而且,在 2021 年,疟疾仍导致约 620,000 人死亡。这是令人震惊、悲伤和可以预防的。但今年是取得惊人进步的一年。\r\n\r\n一种称为 R21/Matrix-M 的疟疾疫苗在四个非洲国家进行了 III 期试验。它在幼儿中的总体疗效为 [75%](https://www.medpagetoday.com/meetingcoverage/astmh/101561)。这是个好消息。在马里进行的一项 II 期试验还测试了一种名为 CIS43LS 的抗体,用于对抗健康成人中的恶性疟原虫感染。在六个月的时间里,单次注射的疗效为 [88.2%](https://www.nejm.org/doi/full/10.1056/NEJMoa2206966)。\r\n\r\n不过,唯一能有效预防疟疾 90% 以上的免疫原是子孢子,这是一种在蚊子生命周期中形成的类孢子部分。这些子孢子被注射到手臂中并[用作疫苗](https://www.science.org/doi/10.1126/scitranslmed.abj3776),但显然很难从真正的蚊子身上收集到这些东西。\r\n\r\n本月早些时候,研究人员在实验室中创造了 "[数亿](https://www.nature.com/articles/s41586-022-05466-7)" 子孢子,而不需要蚊子。他们基本上重新创建了整个"疟原虫从传染性配子体到传染性配子体的全部生命周期,而不需要蚊子。" 这项新技术将有助于更快、更便宜地研制出抗疟疾疫苗。\r\n\r\n

\r\n
\r\n

', 'bodyText': '作者 | Niko McCarty\n翻译 | 章鱼猫先生\n日期 | 原文发表于 2022.12.10\n来源 | Biology Breakthroughs of 2022 - Codon\n\n\n您正在阅读 Codon,这是一份关于生物 + 技术进步和为人类创造更光明未来的想法的时事通讯。\n这是今年的最后一部作品。几周后我会在这里见到你!\n\n\n\n \n 大约 1950 年代,戴着加压氧气面罩的男子\n\n\n"当你经历历史时,历史永远不会像历史。它总是看起来很混乱和凌乱,而且总是让人感觉不舒服。"\n—— 约翰·W·加德纳\n\n许多我非常敬佩的作家都对“进步的停滞”写出了令人信服的论战。科学越来越难,发现越来越小(平均而言),这两件事都很糟糕。\n如果你召集来自世界顶级院系的 93 位物理学家,让他们将 1910 年代获得诺贝尔奖的发现与 80 年代的另一个发现进行比较,他们通常会说更早的发现更重要。\n与五十年前相比,今天实现技术飞跃也更加困难。将计算机芯片上的晶体管数量增加一倍(又名摩尔定律)需要的研究人员数量是 1970 年代初期的 18 倍。今天发表的学术论文被美国专利引用的可能性不到 30 年前发表的论文的一半。\n这些不断缩减的回报正处于历史高位之中。\n美国每年授予超过 50,000 个科学和工程博士学位;这个数字在 1960 年还不到 10,000。联邦对科学的资助也(基本上)处于历史最高水平。科学论文的总数呈指数级增长,但每篇论文的平均作者人数在过去一百年里大约翻了两番。\n\n \n From "The Science of Science" by Wang and Barabási.\n\n出于某种原因,这些都是生物学进步的不完美指标。但是有很多零散的证据表明,科学正在变得越来越不划算,即使感觉进步从未像现在这样快。我相信——基于轶事证据,真的——如果以每年获得诺贝尔奖的发现为基准,生物技术不会停滞不前。只是诺贝尔奖每年都会颁发一次,而且不乏令人惊叹的论文在排队等待获得最高奖项。所以,当然,并不是每个有价值的人都会赢。\n哦,如果你拿我之前提到的物理学调查结果,对医学和化学做同样的实验,结果就会颠倒过来——20 世纪下半叶发现的相对重要性超过了上半叶。\n不管停滞与否,生物学都存在巨大的低效率。它可以——应该!- 移动得更快。\n许多论文需要一年多的时间才能发表,在期刊官僚的严密监视下,被搁置在数字化的边缘。漫长的等待可能也不值得——同行评审通常是无用的,而且很多糟糕的科学无论如何都能通过。许多伟大的想法也从来没有发表在论文上,因为,好吧,他们从来没有得到资助。NIH 拨款审查非常不一致。如果您向 43 位不同的审稿人提供 25 份拨款建议,他们的评定者间可靠性(衡量分数一致性的指标)基本上为零,即使拨款已经获得资金和先前评审小组的高分!给予相同审稿人的无资金资助与有资金资助的资助得分一样。\n那么生物学文献呢?那也是一团糟。山姆·罗德里克斯 (Sam Rodriques) 在最近的一篇文章中写道,科学论文“因委托而变得不可靠”,并且“因遗漏而变得不可靠”。换句话说,一些研究(一小部分)只是编造的。教授或学生为了发表论文而捏造数字,如果有人说他们在胡说八道,编辑可能要过好几年才会撤稿。\n不过,更大的问题可能是疏忽。科学期刊喜欢发表积极的结果,所以大多数消极的发现永远不会出现在光鲜的期刊上。如果有人进行的实验表明药物 A 与受体 B 结合,他们会发表它——但忽略提及药物 A 不会通过 Z 与受体 C 结合。无效结果很少传给科学家,他们中的许多人已经几个月来一次又一次尝试实验的痛苦经历,后来才发现 1970 年代的一篇不起眼的论文使他们所有的努力都变得毫无意义。\n我告诉你这些悲伤的事情——停滞不前的科学和可怕的低效率的故事——是为了说明一个观点:生物学在去年取得了如此大的进步,真是令人惊讶。生物学的进步证明了人类渴望探索、失败,然后继续前进的愿望。这份时事通讯庆祝人类的成就,并重点介绍了过去 12 个月生物学领域的十大进步。\n此列表中的所有内容均来自 Codon 的上一期,因此希望您能在评论中指出我的错误和遗漏。我的入选标准很简单:该列表仅包括 2022 年期间发布到 bioRxiv 或发表在期刊上的论文。我不包括公司成就——这实际上可能是它自己的列表——除非他们发布了数据。(入选)列表中的一些项目包括了多篇论文,因为整个子领域发展得非常快。\n汇总“十佳排名”最大的危险是完全主观的,有很多优秀的东西没有入选,而且很多其他作家已经做到了(虽然我还没有看到专门针对生物学的清单)。诺亚·史密斯 (Noah Smith) 发布了他 2023 年的技术乐观主义清单 (techno-optimism list),其中包括对生物技术的简要提及,而《大西洋月刊》(The Atlantic) 发表了他们的 "年度突破 (breakthroughs of the year)",然后立即将该文章设置为付费文章。\n然而,有必要专门为生物学列出一份完整的榜单,因为很多伟大的事情在人工智能的阴影下被忽略了。人类基因组计划(始于 1990 年)终于在今年完成了,一个庞大的科学家团队填补了最后 8% 的序列空白。科学家们还使用 mirror-image DNA 聚合酶制作了镜像 DNA (mirror-image DNA),并发现了一类新的 CRISPR 蛋白质,它们可以剪切蛋白质而不是基因。机器学习正在蛋白质工程中掀起波澜,例如有一种基于算法被设计出来的酶,这种酶可以比自然界中发现的任何酶更快地分解 PET 塑料。\n我不确定今年的进展是否与生物进展是否整体停滞不前有关。但有一件事是不变的:生物学变得越来越奇怪,而我会一直关注它。\n10. 走向合成细胞\n从纯化学成分构建合成细胞是生物学的圣杯。如果实现了这一壮举,将证明我们已足够详细地理解生命运作的大体轮廓,并有足够的细节可以在实验室中重现它。这也将成为定制细胞的起点,这些细胞可以检测有毒污染或制造药物,同时又不会成为生物安全风险或存在感染风险。\n今年有几篇论文推动了合成细胞的发展,但其中有两篇让人印象深刻。第一篇是在 bioRxiv 上发表的预印本,据称是首次证明核糖体(大分子蛋白质,负责合成其他蛋白质)可以在活细胞之外制造。这是在合成细胞内从头生产蛋白质的重要起点。\n我们还在合成细胞分裂方面取得了重要进展。一项研究报告说,仅使用五种蛋白质就可以在脂肪泡中制造合成分裂环!当这些蛋白质聚集在一起时,它们会收缩并向气泡施加力(下面的 GIF)。\n\n \n 合成分裂环在气泡内形成的延时摄影\n\n9. 更好的碱基编辑器\n早在 2016 年,《自然》杂志的一篇论文就报道了第一个碱基编辑蛋白,它可以将 DNA 中的 "C" 替换为 "T",而无需将基因组一分为二。它的重要性立即显而易见——许多严重的遗传疾病是由 DNA 中的单个碱基交换引起的,现在这些突变可以被修复。\n碱基编辑器已经成熟。这些基因编辑蛋白在发明后仅仅五年就以创纪录的速度进入临床试验,目前 Verve、Beam 和其他公司正在进行针对镰状细胞病、高胆固醇和 Stargardt 病的试验。\n然而,碱基编辑的主要挑战之一是编辑线粒体基因组很棘手,许多遗传疾病都源于此。早在 2020 年,一篇论文就表明碱基编辑器可以成功进入线粒体并使 "C" 变为 "T",但其前景并不乐观。今年 5 月,一篇后续论文称,实际上,这些线粒体基因编辑器诱发了 "大量" 脱靶突变,这意味着它们编辑的位置比预期的要多,弊大于利。\n但创新不会因失败而受阻。仅今年一年就至少发表了三篇论文,使线粒体碱基编辑器变得更小或更准确。让碱基编辑酶进入线粒体或编辑其 DNA 从未如此简单。我相信我们很快就会看到一些针对线粒体相关疾病的临床试验。\n8. 噬菌体传播病毒\n今年对噬菌体来说是个好年头。这真的很合适,因为它也是 Felix d\'Herelle 著名实验 100 周年纪念日。1922 年,这位巴黎微生物学家证明噬菌体(感染细菌的小病毒)可以根除兔子和小动物体内的 "痢疾杆菌和其他杆菌"。\n我们现在正经历着临床疗法的准复兴时期,噬菌体经常被用来消除抗生素无效的感染(尤其是在欧洲医院)。几周前,一个欧洲科学家团队使用实验性噬菌体疗法挽救了一名幼儿的生命。器官移植后,这个小男孩感染了抗生素无法清除的耐药性感染。在用定制的噬菌体鸡尾酒 (a custom-made phage cocktail) 治疗两年多后,孩子在家中恢复了健康。\n5 月,丹佛的一个团队使用噬菌体治疗一名患有严重囊性纤维化的男孩的脓肿分枝杆菌感染。噬菌体将感染控制了一年多,直到获得供体肺。我相信我们会在 2023 年看到定制噬菌体疗法进入临床。\n\n \n\n7. 血友病基因疗法\nHemgenix 是一种治疗 B 型血友病的基因疗法,几个月前获得了 FDA 的批准。它的价格达到了 350 万美元,使其成为有史以来最昂贵的药物(这并不好)。根据 III 期临床试验数据,它在患者的是安全有效期至少两年。\n血友病 A 的基因治疗进展缓慢,该病由一种名为 VIII 的不同凝血蛋白突变引起。5 月的一项研究表明,针对肝脏的基因疗法在非人类灵长类动物中效果很好,可以导致 "总凝血因子 VIII 输出增加 10 倍以上"。3 月份发表的一项有 134 名参与者参与的 I/II 期临床试验表明,使用腺相关病毒进行的基因疗法,也用于肝脏,可减少血友病患者的出血事件。但是,它带来了很多副作用;每个试验参与者至少有一次不良事件。尽管如此,血友病仍是基因治疗的 "低悬" 目标之一,这些试验是其他正在进行中的目标的有用酸性测试。\n6. 合成胚胎\n今年,从老鼠身上采集的干细胞被用来制造 "类胚胎结构",其中包含工作的肠道、跳动的心脏和头脑的雏形,而不需要精子或卵子。\n以色列的 Jacob Hanna 团队发表了一篇最初的论文,于 8 月在 Cell 上发表。据《卫报》报道,这些作者后来成立了一家名为 Renewal Bio 的公司,"旨在培养人类合成胚胎,为医疗条件提供组织和细胞"。剑桥大学和加州理工学院的一个团队也在 8 月 2 日发布了一份预印本,表明这些 "合成胚胎"准确地概括了 "从胚胎第 5.5 天到第 8.5 天的发育事件,包括原肠胚形成、前后轴的形成、大脑,跳动的心脏结构,以及胚胎外组织(包括卵黄囊和绒毛膜)的发育。"\n合成胚胎——正确形成的概率只有 0.5% 左右——有几个潜在的用途。例如,这些结构可以用于研究器官在发育过程中的形成,也可用于在不使用真实胚胎的情况下测试药物。\n\n \n Embryoids after six days. From Kasey Lau et al. on bioRxiv. Link\n\n5. 细胞重编程\n今年的一大亮点:首次证明仅靠化学物质就能将人体细胞重新编程为干细胞。这一突破需要十多年的时间,并需使用 11 种不同的化学物质,以及一到两个月的工作时间,所以仍需要一些微调。早在 2013 年,同一个小组就已使用这种方法实现了小鼠细胞的转化,但人类细胞的转化过程要困难得多。\n这也不是第一项重新编程人类细胞的研究。这一荣誉属于山中伸弥 (Shinya Yamanaka),他在 2006 年通过表达四种蛋白质(现在著名的 "Yamanaka 因子")对 iPS 细胞进行了重编程。在随后的几十年中,其他研究小组使用病毒或 mRNA 对细胞进行重编程。但这种仅使用化学物质的方法脱颖而出,因为它在体外使用简单,而且化学混合物可以通过静脉注射输送到体内——不需要基因编辑。该方法提供了一种相对简单的工具来生成可用于再生医学的人类多能干细胞。\n4. 植物更容易设计\n我们生活在人类世,这是人类历史上一个可怕的时刻,人造材料的重量超过地球上所有的生物量,而且重量每年都在继续增加一倍。\n\n \n "Global human-made mass exceeds all living biomass," by Elhacham E et al. in Nature. Link\n\n在我们现有的生物质中,据估计有 83% 由植物持有。如果我们想要走出这场行星垃圾场的困境,那么,那么我们可能不得不对植物进行工程改造:让它们捕获更多的碳,增强它们的光合作用,种植生产更多的食物,等等!\n幸运的是,做到这一点从未如此简单。几十年来,合成生物学家已经对细菌和哺乳动物细胞进行了改造,使其具有越来越复杂的遗传回路,即使植物在很大程度上被忽视了。今年,两项重要进展改变了平衡。\n先是基因编辑技术,如 CRISPR,现在已经过优化,可以在植物中更好地发挥作用。例如,Prime 编辑器是可以插入、删除或交换 DNA 的 "搜索和替换" 基因编辑器。与其他 Prime 编辑器相比,新的 Plant Prime Editor 在植物细胞中的效率提高了 3.4 倍,并被用于在实验室中迅速使水稻植物对除草剂产生耐受性。\n但更大的进步是:斯坦福大学的一个团队发布了一个完整的基因工具包,可以像我们对细菌进行编程一样对植物进行 "编程"。新工具包包括大量合成启动子和转录因子,可用于控制植物中的基因表达。这些遗传部分被用于构建能够在本塞姆氏烟草和拟南芥中进行布尔逻辑运算的基因回路。作者还建立了逻辑门,可以控制植物根部的基因表达水平,从而控制它们的侧向密度。\n\n \n A genetic circuit controls how many lateral roots shoot out from a plant’s roots. Lateral density increases from left to right, with a wildtype plant shown on the far right. From Brophy et al. on bioRxiv.\n\n3. 走向负碳\n生物学的一个众所周知的困难部分是难以扩展(进行大规模的研究)。在试管中改造一个能将糖转化为抗癌药物的细胞是一回事,但在一个千升生物反应器中做同样的事却是完全不同的挑战。\n这就是像 LanzaTech 这样的公司令人兴奋的原因。他们实际上已经在工业工厂扩大了生物学规模。他们有试点设施,将工厂的废碳回收成燃料和化学品。这些工厂每年可以生产数千亿加仑的燃料,并且已经达到相当于每年减少数千辆汽车上路的排放量。\n几个月前,来自 LanzaTech 和西北大学的科学家们达到了另一个里程碑:使用一种名为 Clostridium autoethanogenum 的工程自养生物,他们在具有负碳足迹的过程中以工业规模生产丙酮和异丙醇。 "与导致温室气体释放的传统生产过程不同,我们的过程可以固定碳," 他们在发表的论文中写道。这是大规模生物学向前迈出的一大步。经过改造的微生物可以在不拖累大气的情况下改善污染物并产生化学物质。\n2. 异种移植成为现实\n这将作为 "异种移植年" 载入人类史册。异种移植的历史可以追溯到 20 世纪 60 年代中期——法国外科医生勒内·库斯 (Renè Kuss) 将猪肾移植到人体中,结果很快被患者的身体排斥——异种移植一直是一个失败的领域。最著名的例子可能是 80 年代 Stephanie Beauclair 或 Baby Fae 的手术,她从狒狒那里接受了一颗心脏,但不久后就去世了。\n不过,在过去四十年里,我们在从猪身上提取心脏并将其植入人体方面做得更好,因为基因编辑技术正在改进。现在比以往任何时候都更容易在猪的细胞中找到所有导致我们的身体排斥该器官的有害蛋白质,并从基因组中系统地消除这些蛋白质编码基因。但进步从来都不是没有陷阱的。\n今年 1 月 7 日,马里兰大学的一组外科医生将一颗猪的心脏移植到 57 岁的老大卫贝内特体内,两个月后他去世了。\n5 月,两只猪的肾脏被移植到脑死亡患者体内,并进行了 54 小时的监测,这让沮丧过后变得乐观起来。两个肾脏都产生了尿液,活组织检查没有显示出任何器官排斥的迹象。\n心脏移植可能因为器官感染了猪病毒而失败,但肾移植研究的作者没有检测到这种病毒。猪肾可能很快就会进入人们的生活。\n1. 我们离终结疟疾从未如此近\n如果您相信约翰·惠特菲尔德 (John Whitfield) 2002 年在《自然》杂志发表的这篇文章(该说法未被引用),"疟疾已经杀死了所有曾经生活过的人的一半"。即使该说法是错误的,在整个人类历史上,蚊子也已经集体杀死了数十亿人。昆虫混蛋干掉了亚历山大大帝、哥特人阿拉里克和但丁。而且,在 2021 年,疟疾仍导致约 620,000 人死亡。这是令人震惊、悲伤和可以预防的。但今年是取得惊人进步的一年。\n一种称为 R21/Matrix-M 的疟疾疫苗在四个非洲国家进行了 III 期试验。它在幼儿中的总体疗效为 75%。这是个好消息。在马里进行的一项 II 期试验还测试了一种名为 CIS43LS 的抗体,用于对抗健康成人中的恶性疟原虫感染。在六个月的时间里,单次注射的疗效为 88.2%。\n不过,唯一能有效预防疟疾 90% 以上的免疫原是子孢子,这是一种在蚊子生命周期中形成的类孢子部分。这些子孢子被注射到手臂中并用作疫苗,但显然很难从真正的蚊子身上收集到这些东西。\n本月早些时候,研究人员在实验室中创造了 "数亿" 子孢子,而不需要蚊子。他们基本上重新创建了整个"疟原虫从传染性配子体到传染性配子体的全部生命周期,而不需要蚊子。" 这项新技术将有助于更快、更便宜地研制出抗疟疾疫苗。', 'bodyHTML': '
\n

作者 | Niko McCarty
\n翻译 | 章鱼猫先生
\n日期 | 原文发表于 2022.12.10
\n来源 | Biology Breakthroughs of 2022 - Codon

\n
\n
\n

您正在阅读 Codon,这是一份关于生物 + 技术进步和为人类创造更光明未来的想法的时事通讯。
\n这是今年的最后一部作品。几周后我会在这里见到你!

\n
\n\n

\n
\n 大约 1950 年代,戴着加压氧气面罩的男子\n

\n
\n

"当你经历历史时,历史永远不会像历史。它总是看起来很混乱和凌乱,而且总是让人感觉不舒服。"
\n—— 约翰·W·加德纳

\n
\n

许多我非常敬佩的作家都对“进步的停滞”写出了令人信服的论战。科学越来越难,发现越来越小(平均而言),这两件事都很糟糕。

\n

如果你召集来自世界顶级院系的 93 位物理学家,让他们将 1910 年代获得诺贝尔奖的发现与 80 年代的另一个发现进行比较,他们通常会说更早的发现更重要。

\n

与五十年前相比,今天实现技术飞跃也更加困难。将计算机芯片上的晶体管数量增加一倍(又名摩尔定律)需要的研究人员数量是 1970 年代初期的 18 倍。今天发表的学术论文被美国专利引用的可能性不到 30 年前发表的论文的一半

\n

这些不断缩减的回报正处于历史高位之中。

\n

美国每年授予超过 50,000 个科学和工程博士学位;这个数字在 1960 年还不到 10,000。联邦对科学的资助也(基本上)处于历史最高水平。科学论文的总数呈指数级增长,但每篇论文的平均作者人数在过去一百年里大约翻了两番。

\n

\n
\n From "The Science of Science" by Wang and Barabási.\n

\n

出于某种原因,这些都是生物学进步的不完美指标。但是有很多零散的证据表明,科学正在变得越来越不划算,即使感觉进步从未像现在这样快。我相信——基于轶事证据,真的——如果以每年获得诺贝尔奖的发现为基准,生物技术不会停滞不前。只是诺贝尔奖每年都会颁发一次,而且不乏令人惊叹的论文在排队等待获得最高奖项。所以,当然,并不是每个有价值的人都会赢。

\n

哦,如果你拿我之前提到的物理学调查结果,对医学和化学做同样的实验,结果就会颠倒过来——20 世纪下半叶发现的相对重要性超过了上半叶。

\n

不管停滞与否,生物学都存在巨大的低效率。它可以——应该!- 移动得更快。

\n

许多论文需要一年多的时间才能发表,在期刊官僚的严密监视下,被搁置在数字化的边缘。漫长的等待可能也不值得——同行评审通常是无用的,而且很多糟糕的科学无论如何都能通过。许多伟大的想法也从来没有发表在论文上,因为,好吧,他们从来没有得到资助。NIH 拨款审查非常不一致。如果您向 43 位不同的审稿人提供 25 份拨款建议,他们的评定者间可靠性(衡量分数一致性的指标)基本上为零,即使拨款已经获得资金和先前评审小组的高分!给予相同审稿人的无资金资助与有资金资助的资助得分一样。

\n

那么生物学文献呢?那也是一团糟。山姆·罗德里克斯 (Sam Rodriques) 在最近的一篇文章中写道,科学论文“因委托而变得不可靠”,并且“因遗漏而变得不可靠”。换句话说,一些研究(一小部分)只是编造的。教授或学生为了发表论文而捏造数字,如果有人说他们在胡说八道,编辑可能要过好几年才会撤稿。

\n

不过,更大的问题可能是疏忽。科学期刊喜欢发表积极的结果,所以大多数消极的发现永远不会出现在光鲜的期刊上。如果有人进行的实验表明药物 A 与受体 B 结合,他们会发表它——但忽略提及药物 A 不会通过 Z 与受体 C 结合。无效结果很少传给科学家,他们中的许多人已经几个月来一次又一次尝试实验的痛苦经历,后来才发现 1970 年代的一篇不起眼的论文使他们所有的努力都变得毫无意义。

\n

我告诉你这些悲伤的事情——停滞不前的科学和可怕的低效率的故事——是为了说明一个观点:生物学在去年取得了如此大的进步,真是令人惊讶。生物学的进步证明了人类渴望探索、失败,然后继续前进的愿望。这份时事通讯庆祝人类的成就,并重点介绍了过去 12 个月生物学领域的十大进步

\n

此列表中的所有内容均来自 Codon 的上一期,因此希望您能在评论中指出我的错误和遗漏。我的入选标准很简单:该列表仅包括 2022 年期间发布到 bioRxiv 或发表在期刊上的论文。我不包括公司成就——这实际上可能是它自己的列表——除非他们发布了数据。(入选)列表中的一些项目包括了多篇论文,因为整个子领域发展得非常快。

\n

汇总“十佳排名”最大的危险是完全主观的,有很多优秀的东西没有入选,而且很多其他作家已经做到了(虽然我还没有看到专门针对生物学的清单)。诺亚·史密斯 (Noah Smith) 发布了他 2023 年的技术乐观主义清单 (techno-optimism list),其中包括对生物技术的简要提及,而《大西洋月刊》(The Atlantic) 发表了他们的 "年度突破 (breakthroughs of the year)",然后立即将该文章设置为付费文章。

\n

然而,有必要专门为生物学列出一份完整的榜单,因为很多伟大的事情在人工智能的阴影下被忽略了。人类基因组计划(始于 1990 年)终于在今年完成了,一个庞大的科学家团队填补了最后 8% 的序列空白。科学家们还使用 mirror-image DNA 聚合酶制作了镜像 DNA (mirror-image DNA),并发现了一类新的 CRISPR 蛋白质,它们可以剪切蛋白质而不是基因。机器学习正在蛋白质工程中掀起波澜,例如有一种基于算法被设计出来的酶,这种酶可以比自然界中发现的任何酶更快地分解 PET 塑料

\n

我不确定今年的进展是否与生物进展是否整体停滞不前有关。但有一件事是不变的:生物学变得越来越奇怪,而我会一直关注它。

\n

10. 走向合成细胞

\n

从纯化学成分构建合成细胞是生物学的圣杯。如果实现了这一壮举,将证明我们已足够详细地理解生命运作的大体轮廓,并有足够的细节可以在实验室中重现它。这也将成为定制细胞的起点,这些细胞可以检测有毒污染或制造药物,同时又不会成为生物安全风险或存在感染风险。

\n

今年有几篇论文推动了合成细胞的发展,但其中有两篇让人印象深刻。第一篇是在 bioRxiv 上发表的预印本,据称是首次证明核糖体(大分子蛋白质,负责合成其他蛋白质)可以在活细胞之外制造。这是在合成细胞内从头生产蛋白质的重要起点。

\n

我们还在合成细胞分裂方面取得了重要进展。一项研究报告说,仅使用五种蛋白质就可以在脂肪泡中制造合成分裂环!当这些蛋白质聚集在一起时,它们会收缩并向气泡施加力(下面的 GIF)。

\n

\n
\n 合成分裂环在气泡内形成的延时摄影\n

\n

9. 更好的碱基编辑器

\n

早在 2016 年,《自然》杂志的一篇论文就报道了第一个碱基编辑蛋白,它可以将 DNA 中的 "C" 替换为 "T",而无需将基因组一分为二。它的重要性立即显而易见——许多严重的遗传疾病是由 DNA 中的单个碱基交换引起的,现在这些突变可以被修复。

\n

碱基编辑器已经成熟。这些基因编辑蛋白在发明后仅仅五年就以创纪录的速度进入临床试验,目前 Verve、Beam 和其他公司正在进行针对镰状细胞病、高胆固醇和 Stargardt 病的试验

\n

然而,碱基编辑的主要挑战之一是编辑线粒体基因组很棘手,许多遗传疾病都源于此。早在 2020 年,一篇论文就表明碱基编辑器可以成功进入线粒体并使 "C" 变为 "T",但其前景并不乐观。今年 5 月,一篇后续论文称,实际上,这些线粒体基因编辑器诱发了 "大量" 脱靶突变,这意味着它们编辑的位置比预期的要多,弊大于利。

\n

但创新不会因失败而受阻。仅今年一年就至少发表了三篇论文,使线粒体碱基编辑器变得更小更准确。让碱基编辑酶进入线粒体或编辑其 DNA 从未如此简单。我相信我们很快就会看到一些针对线粒体相关疾病的临床试验。

\n

8. 噬菌体传播病毒

\n

今年对噬菌体来说是个好年头。这真的很合适,因为它也是 Felix d\'Herelle 著名实验 100 周年纪念日。1922 年,这位巴黎微生物学家证明噬菌体(感染细菌的小病毒)可以根除兔子和小动物体内的 "痢疾杆菌和其他杆菌"。

\n

我们现在正经历着临床疗法的准复兴时期,噬菌体经常被用来消除抗生素无效的感染(尤其是在欧洲医院)。几周前,一个欧洲科学家团队使用实验性噬菌体疗法挽救了一名幼儿的生命。器官移植后,这个小男孩感染了抗生素无法清除的耐药性感染。在用定制的噬菌体鸡尾酒 (a custom-made phage cocktail) 治疗两年多后,孩子在家中恢复了健康。

\n

5 月,丹佛的一个团队使用噬菌体治疗一名患有严重囊性纤维化的男孩的脓肿分枝杆菌感染。噬菌体将感染控制了一年多,直到获得供体肺。我相信我们会在 2023 年看到定制噬菌体疗法进入临床。

\n

\n
\n

\n

7. 血友病基因疗法

\n

Hemgenix 是一种治疗 B 型血友病的基因疗法,几个月前获得了 FDA 的批准。它的价格达到了 350 万美元,使其成为有史以来最昂贵的药物(这并不好)。根据 III 期临床试验数据,它在患者的是安全有效期至少两年

\n

血友病 A 的基因治疗进展缓慢,该病由一种名为 VIII 的不同凝血蛋白突变引起。5 月的一项研究表明,针对肝脏的基因疗法在非人类灵长类动物中效果很好,可以导致 "总凝血因子 VIII 输出增加 10 倍以上"。3 月份发表的一项有 134 名参与者参与的 I/II 期临床试验表明,使用腺相关病毒进行的基因疗法,也用于肝脏,可减少血友病患者的出血事件。但是,它带来了很多副作用;每个试验参与者至少有一次不良事件。尽管如此,血友病仍是基因治疗的 "低悬" 目标之一,这些试验是其他正在进行中的目标的有用酸性测试。

\n

6. 合成胚胎

\n

今年,从老鼠身上采集的干细胞被用来制造 "类胚胎结构",其中包含工作的肠道、跳动的心脏和头脑的雏形,而不需要精子或卵子。

\n

以色列的 Jacob Hanna 团队发表了一篇最初的论文,于 8 月在 Cell 上发表。据《卫报》报道,这些作者后来成立了一家名为 Renewal Bio 的公司,"旨在培养人类合成胚胎,为医疗条件提供组织和细胞"。剑桥大学和加州理工学院的一个团队也在 8 月 2 日发布了一份预印本,表明这些 "合成胚胎"准确地概括了 "从胚胎第 5.5 天到第 8.5 天的发育事件,包括原肠胚形成、前后轴的形成、大脑,跳动的心脏结构,以及胚胎外组织(包括卵黄囊和绒毛膜)的发育。"

\n

合成胚胎——正确形成的概率只有 0.5% 左右——有几个潜在的用途。例如,这些结构可以用于研究器官在发育过程中的形成,也可用于在不使用真实胚胎的情况下测试药物。

\n

\n
\n Embryoids after six days. From Kasey Lau et al. on bioRxiv. Link\n

\n

5. 细胞重编程

\n

今年的一大亮点:首次证明仅靠化学物质就能将人体细胞重新编程为干细胞。这一突破需要十多年的时间,并需使用 11 种不同的化学物质,以及一到两个月的工作时间,所以仍需要一些微调。早在 2013 年,同一个小组就已使用这种方法实现了小鼠细胞的转化,但人类细胞的转化过程要困难得多。

\n

这也不是第一项重新编程人类细胞的研究。这一荣誉属于山中伸弥 (Shinya Yamanaka),他在 2006 年通过表达四种蛋白质(现在著名的 "Yamanaka 因子")对 iPS 细胞进行了重编程。在随后的几十年中,其他研究小组使用病毒或 mRNA 对细胞进行重编程。但这种仅使用化学物质的方法脱颖而出,因为它在体外使用简单,而且化学混合物可以通过静脉注射输送到体内——不需要基因编辑。该方法提供了一种相对简单的工具来生成可用于再生医学的人类多能干细胞。

\n

4. 植物更容易设计

\n

我们生活在人类世,这是人类历史上一个可怕的时刻,人造材料的重量超过地球上所有的生物量,而且重量每年都在继续增加一倍。

\n

\n
\n "Global human-made mass exceeds all living biomass," by Elhacham E et al. in Nature. Link\n

\n

在我们现有的生物质中,据估计有 83% 由植物持有。如果我们想要走出这场行星垃圾场的困境,那么,那么我们可能不得不对植物进行工程改造:让它们捕获更多的碳,增强它们的光合作用,种植生产更多的食物,等等!

\n

幸运的是,做到这一点从未如此简单。几十年来,合成生物学家已经对细菌和哺乳动物细胞进行了改造,使其具有越来越复杂的遗传回路,即使植物在很大程度上被忽视了。今年,两项重要进展改变了平衡。

\n

先是基因编辑技术,如 CRISPR,现在已经过优化,可以在植物中更好地发挥作用。例如,Prime 编辑器是可以插入、删除或交换 DNA 的 "搜索和替换" 基因编辑器。与其他 Prime 编辑器相比,新的 Plant Prime Editor 在植物细胞中的效率提高了 3.4 倍,并被用于在实验室中迅速使水稻植物对除草剂产生耐受性。

\n

但更大的进步是:斯坦福大学的一个团队发布了一个完整的基因工具包,可以像我们对细菌进行编程一样对植物进行 "编程"。新工具包包括大量合成启动子和转录因子,可用于控制植物中的基因表达。这些遗传部分被用于构建能够在本塞姆氏烟草和拟南芥中进行布尔逻辑运算的基因回路。作者还建立了逻辑门,可以控制植物根部的基因表达水平,从而控制它们的侧向密度。

\n

\n
\n A genetic circuit controls how many lateral roots shoot out from a plant’s roots. Lateral density increases from left to right, with a wildtype plant shown on the far right. From Brophy et al. on bioRxiv.\n

\n

3. 走向负碳

\n

生物学的一个众所周知的困难部分是难以扩展(进行大规模的研究)。在试管中改造一个能将糖转化为抗癌药物的细胞是一回事,但在一个千升生物反应器中做同样的事却是完全不同的挑战。

\n

这就是像 LanzaTech 这样的公司令人兴奋的原因。他们实际上已经在工业工厂扩大了生物学规模。他们有试点设施,将工厂的废碳回收成燃料和化学品。这些工厂每年可以生产数千亿加仑的燃料,并且已经达到相当于每年减少数千辆汽车上路的排放量。

\n

几个月前,来自 LanzaTech 和西北大学的科学家们达到了另一个里程碑:使用一种名为 Clostridium autoethanogenum 的工程自养生物,他们在具有负碳足迹的过程中以工业规模生产丙酮和异丙醇。 "与导致温室气体释放的传统生产过程不同,我们的过程可以固定碳," 他们在发表的论文中写道。这是大规模生物学向前迈出的一大步。经过改造的微生物可以在不拖累大气的情况下改善污染物并产生化学物质。

\n

2. 异种移植成为现实

\n

这将作为 "异种移植年" 载入人类史册。异种移植的历史可以追溯到 20 世纪 60 年代中期——法国外科医生勒内·库斯 (Renè Kuss) 将猪肾移植到人体中,结果很快被患者的身体排斥——异种移植一直是一个失败的领域。最著名的例子可能是 80 年代 Stephanie Beauclair 或 Baby Fae 的手术,她从狒狒那里接受了一颗心脏,但不久后就去世了。

\n

不过,在过去四十年里,我们在从猪身上提取心脏并将其植入人体方面做得更好,因为基因编辑技术正在改进。现在比以往任何时候都更容易在猪的细胞中找到所有导致我们的身体排斥该器官的有害蛋白质,并从基因组中系统地消除这些蛋白质编码基因。但进步从来都不是没有陷阱的。

\n

今年 1 月 7 日,马里兰大学的一组外科医生将一颗猪的心脏移植到 57 岁的老大卫贝内特体内,两个月后他去世了。

\n

5 月,两只猪的肾脏被移植到脑死亡患者体内,并进行了 54 小时的监测,这让沮丧过后变得乐观起来。两个肾脏都产生了尿液,活组织检查没有显示出任何器官排斥的迹象。

\n

心脏移植可能因为器官感染了猪病毒而失败,但肾移植研究的作者没有检测到这种病毒。猪肾可能很快就会进入人们的生活。

\n

1. 我们离终结疟疾从未如此近

\n

如果您相信约翰·惠特菲尔德 (John Whitfield) 2002 年在《自然》杂志发表的这篇文章(该说法未被引用),"疟疾已经杀死了所有曾经生活过的人的一半"。即使该说法是错误的,在整个人类历史上,蚊子也已经集体杀死了数十亿人。昆虫混蛋干掉了亚历山大大帝、哥特人阿拉里克和但丁。而且,在 2021 年,疟疾仍导致约 620,000 人死亡。这是令人震惊、悲伤和可以预防的。但今年是取得惊人进步的一年。

\n

一种称为 R21/Matrix-M 的疟疾疫苗在四个非洲国家进行了 III 期试验。它在幼儿中的总体疗效为 75%。这是个好消息。在马里进行的一项 II 期试验还测试了一种名为 CIS43LS 的抗体,用于对抗健康成人中的恶性疟原虫感染。在六个月的时间里,单次注射的疗效为 88.2%

\n

不过,唯一能有效预防疟疾 90% 以上的免疫原是子孢子,这是一种在蚊子生命周期中形成的类孢子部分。这些子孢子被注射到手臂中并用作疫苗,但显然很难从真正的蚊子身上收集到这些东西。

\n

本月早些时候,研究人员在实验室中创造了 "数亿" 子孢子,而不需要蚊子。他们基本上重新创建了整个"疟原虫从传染性配子体到传染性配子体的全部生命周期,而不需要蚊子。" 这项新技术将有助于更快、更便宜地研制出抗疟疾疫苗。

\n

\n
\n

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.3-资讯'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '那些年,和微信公众号编辑器战斗的日子', 'number': 31, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/31', 'createdAt': '2023-12-01T03:10:07Z', 'lastEditedAt': '2023-12-01T05:35:04Z', 'updatedAt': '2024-01-04T05:44:14Z', 'body': "看到 HelloGitHub 公众号在 2019-09-25 发表的这篇文章《[和微信公众号编辑器战斗的日子](https://mp.weixin.qq.com/s/3-A_iSZYD88Cy467qOnNOw)》,结合自己最近折腾的 React 版本应用 [Markdown2Html](https://github.com/shenweiyan/Markdown2Html),也想着来聊几句。\r\n\r\n\r\n\r\n## Md2All\r\n\r\n在使用 Mdnice 前,一直在用 [Md2All](https://md.aclickall.com) 的自搭建版本 [Md2XEditor](https://github.com/shenweiyan/Md2XEditor),这是一个源自 [barretlee](https://github.com/barretlee) 最早在 2017 年的 [online-markdown](https://github.com/barretlee/online-markdown) 项目,经过二次开发而来的 Markdown 在线转换工具。\r\n\r\n个人在 2021 年的时候,浏览 GitHub 无意中发现了 [Md2All](https://md.aclickall.com) 托管在 GitHub 的源码仓库 [github.com/aclickall/aclickall.github.io](https://github.com/aclickall/aclickall.github.io>),Fork 过来,利用自己微薄的前端知识做了一点点修改,才形成了一直使用到今天的 [Md2XEditor](https://github.com/shenweiyan/Md2XEditor)。 \r\n![Md2XEditor v-2.8.5](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/md2xeditor-v2.8.5.png)\r\n\r\n虽然说,Md2All 已经把 Markdown2Html 或者说把 Markdown2WeChat 的大部分功能实现了,但由于它目前能找到的源码都是 **经过 build 构建后可以在生产环境中使用的最终版本的代码**(诸如压缩和优化代码、打包文件、生成静态文件等),功能调整实在太费劲,而且自己对 Node/React 的开发基本是零基础。在没有找到好的替代品前,也只能将就着用,一直用到了 2023 年。\r\n\r\n## markdown-nice\r\n\r\n[Mdnice](https://github.com/mdnice/markdown-nice/) 的项目虽然很早就听说,也曾经试用过一段时间,但是由于收费,加上同样存在 **超链接文字复制到公众号颜色失效** 的问题,所以一直没有深入了解和使用。直到 2023 年下半年看到不少在关注的公众号推文都变换了风格,才知道原来都在用着 Mdnice,于是重新回来一看,发现这个应用原来还是**开源的**,还可以**自己搭建和部署**!\r\n\r\n回来搜了一波 Mdnice,发现 UI 都大同小异,但也发现了 这一个长得很像 Mdnice 又不完全像的平台,从功能和 UI 上它似乎更符合个人的需求和审美,于是去搜源码,果然在 [github.com/TaleAi/markdown2html](https://github.com/TaleAi/markdown2html) 上找到了(虽然这个仓库里面包括 README 在内提供的链接已经失效),但还是果断 Fork 过来,开始了自己部署和折腾之旅。 \r\n![wechat-bmpi-dev](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/wechat-bmpi-dev.png)\r\n\r\n## 一点折腾\r\n\r\n把自己的 Markdown2Html 站点部署起来后,一切看起来都很顺利,但在使用过程中就发现了这个一直存在的问题:**超链接文字复制到公众号颜色失效**!\r\n\r\n于是开始去尝试看看 Mdnice 的源码,从最开始的一头雾水开始到慢慢摸到一点点头绪,也第一次知道了 [markdown-it](https://github.com/markdown-it/markdown-it) 这个目前使用最广泛的 markdown 解析器工具。但功夫不负有心人,借助 ChatGPT 的帮助,最后终于勉勉强强把 **超链接文字复制到公众号颜色失效** 给解决了。\r\n\r\n后面还陆陆续续增加了一些自己喜欢的文章主题,增加了一些网格化的背景等等。由于 Mdnice 使用了非常多的开源插件,所以很多东西改动起来都非常方便。 \r\n![markdown2weixin](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/markdown2wechat.png)\r\n\r\n## 继续更新\r\n\r\n个人 (包括本公众号) 很多的文章都是先写在 GitHub [Knowledge-Garden](https://github.com/shenweiyan/Knowledge-Garden) 仓库的 [Discussions](https://github.com/shenweiyan/Knowledge-Garden/discussions) 上,有了 Markdown2Html 后面想要转到公众号也就很方便了。\r\n\r\n到这里,轮子也总算造完了,又该好好搬砖了。\r\n\r\n希望后面能有更多的东西跟大家分享吧,也希望大家在 GitHub 上多多关注我,一起交流。\r\n\r\n## 参考资料\r\n\r\n1. [Markdown-It 解析原理](https://lq782655835.github.io/blogs/project/markdown-it-code.html) - [springleo's blog](https://lq782655835.github.io/blogs/)", 'bodyText': "看到 HelloGitHub 公众号在 2019-09-25 发表的这篇文章《和微信公众号编辑器战斗的日子》,结合自己最近折腾的 React 版本应用 Markdown2Html,也想着来聊几句。\n\nMd2All\n在使用 Mdnice 前,一直在用 Md2All 的自搭建版本 Md2XEditor,这是一个源自 barretlee 最早在 2017 年的 online-markdown 项目,经过二次开发而来的 Markdown 在线转换工具。\n个人在 2021 年的时候,浏览 GitHub 无意中发现了 Md2All 托管在 GitHub 的源码仓库 github.com/aclickall/aclickall.github.io,Fork 过来,利用自己微薄的前端知识做了一点点修改,才形成了一直使用到今天的 Md2XEditor。\n\n虽然说,Md2All 已经把 Markdown2Html 或者说把 Markdown2WeChat 的大部分功能实现了,但由于它目前能找到的源码都是 经过 build 构建后可以在生产环境中使用的最终版本的代码(诸如压缩和优化代码、打包文件、生成静态文件等),功能调整实在太费劲,而且自己对 Node/React 的开发基本是零基础。在没有找到好的替代品前,也只能将就着用,一直用到了 2023 年。\nmarkdown-nice\nMdnice 的项目虽然很早就听说,也曾经试用过一段时间,但是由于收费,加上同样存在 超链接文字复制到公众号颜色失效 的问题,所以一直没有深入了解和使用。直到 2023 年下半年看到不少在关注的公众号推文都变换了风格,才知道原来都在用着 Mdnice,于是重新回来一看,发现这个应用原来还是开源的,还可以自己搭建和部署!\n回来搜了一波 Mdnice,发现 UI 都大同小异,但也发现了 https://wechat.bmpi.dev/ 这一个长得很像 Mdnice 又不完全像的平台,从功能和 UI 上它似乎更符合个人的需求和审美,于是去搜源码,果然在 github.com/TaleAi/markdown2html 上找到了(虽然这个仓库里面包括 README 在内提供的链接已经失效),但还是果断 Fork 过来,开始了自己部署和折腾之旅。\n\n一点折腾\n把自己的 Markdown2Html 站点部署起来后,一切看起来都很顺利,但在使用过程中就发现了这个一直存在的问题:超链接文字复制到公众号颜色失效!\n于是开始去尝试看看 Mdnice 的源码,从最开始的一头雾水开始到慢慢摸到一点点头绪,也第一次知道了 markdown-it 这个目前使用最广泛的 markdown 解析器工具。但功夫不负有心人,借助 ChatGPT 的帮助,最后终于勉勉强强把 超链接文字复制到公众号颜色失效 给解决了。\n后面还陆陆续续增加了一些自己喜欢的文章主题,增加了一些网格化的背景等等。由于 Mdnice 使用了非常多的开源插件,所以很多东西改动起来都非常方便。\n\n继续更新\n个人 (包括本公众号) 很多的文章都是先写在 GitHub Knowledge-Garden 仓库的 Discussions 上,有了 Markdown2Html 后面想要转到公众号也就很方便了。\n到这里,轮子也总算造完了,又该好好搬砖了。\n希望后面能有更多的东西跟大家分享吧,也希望大家在 GitHub 上多多关注我,一起交流。\n参考资料\n\nMarkdown-It 解析原理 - springleo's blog", 'bodyHTML': '

看到 HelloGitHub 公众号在 2019-09-25 发表的这篇文章《和微信公众号编辑器战斗的日子》,结合自己最近折腾的 React 版本应用 Markdown2Html,也想着来聊几句。

\n\n

Md2All

\n

在使用 Mdnice 前,一直在用 Md2All 的自搭建版本 Md2XEditor,这是一个源自 barretlee 最早在 2017 年的 online-markdown 项目,经过二次开发而来的 Markdown 在线转换工具。

\n

个人在 2021 年的时候,浏览 GitHub 无意中发现了 Md2All 托管在 GitHub 的源码仓库 github.com/aclickall/aclickall.github.io,Fork 过来,利用自己微薄的前端知识做了一点点修改,才形成了一直使用到今天的 Md2XEditor
\nMd2XEditor v-2.8.5

\n

虽然说,Md2All 已经把 Markdown2Html 或者说把 Markdown2WeChat 的大部分功能实现了,但由于它目前能找到的源码都是 经过 build 构建后可以在生产环境中使用的最终版本的代码(诸如压缩和优化代码、打包文件、生成静态文件等),功能调整实在太费劲,而且自己对 Node/React 的开发基本是零基础。在没有找到好的替代品前,也只能将就着用,一直用到了 2023 年。

\n

markdown-nice

\n

Mdnice 的项目虽然很早就听说,也曾经试用过一段时间,但是由于收费,加上同样存在 超链接文字复制到公众号颜色失效 的问题,所以一直没有深入了解和使用。直到 2023 年下半年看到不少在关注的公众号推文都变换了风格,才知道原来都在用着 Mdnice,于是重新回来一看,发现这个应用原来还是开源的,还可以自己搭建和部署

\n

回来搜了一波 Mdnice,发现 UI 都大同小异,但也发现了 https://wechat.bmpi.dev/ 这一个长得很像 Mdnice 又不完全像的平台,从功能和 UI 上它似乎更符合个人的需求和审美,于是去搜源码,果然在 github.com/TaleAi/markdown2html 上找到了(虽然这个仓库里面包括 README 在内提供的链接已经失效),但还是果断 Fork 过来,开始了自己部署和折腾之旅。
\nwechat-bmpi-dev

\n

一点折腾

\n

把自己的 Markdown2Html 站点部署起来后,一切看起来都很顺利,但在使用过程中就发现了这个一直存在的问题:超链接文字复制到公众号颜色失效

\n

于是开始去尝试看看 Mdnice 的源码,从最开始的一头雾水开始到慢慢摸到一点点头绪,也第一次知道了 markdown-it 这个目前使用最广泛的 markdown 解析器工具。但功夫不负有心人,借助 ChatGPT 的帮助,最后终于勉勉强强把 超链接文字复制到公众号颜色失效 给解决了。

\n

后面还陆陆续续增加了一些自己喜欢的文章主题,增加了一些网格化的背景等等。由于 Mdnice 使用了非常多的开源插件,所以很多东西改动起来都非常方便。
\nmarkdown2weixin

\n

继续更新

\n

个人 (包括本公众号) 很多的文章都是先写在 GitHub Knowledge-Garden 仓库的 Discussions 上,有了 Markdown2Html 后面想要转到公众号也就很方便了。

\n

到这里,轮子也总算造完了,又该好好搬砖了。

\n

希望后面能有更多的东西跟大家分享吧,也希望大家在 GitHub 上多多关注我,一起交流。

\n

参考资料

\n
    \n
  1. Markdown-It 解析原理 - springleo\'s blog
  2. \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '单行 Python 代码片段', 'number': 30, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/30', 'createdAt': '2023-12-01T03:05:46Z', 'lastEditedAt': None, 'updatedAt': '2024-01-03T07:56:51Z', 'body': '> Via:https://muhammadraza.me/2023/python-oneliners\r\n\r\n我已经沉浸在 Python 编程世界大约三年了。在这段时间里,我开始欣赏这种多功能语言的优雅和强大。在这篇既有趣又具有教育意义的文章中,我将展示一系列单行 Python 代码片段。无论您是经验丰富的开发人员还是初学者,这些简洁的代码行都可以让您深入了解 Python 的简单性和有效性,它们展示一行代码如何完成在其他语言中可能需要几行代码才能完成的任务。\r\n\r\n\r\n\r\n- 反转字符串\r\n```python\r\nreversed_string = "Hello World"[::-1]\r\n```\r\n\r\n- 检查数字是否为偶数\r\n```python\r\nis_even = lambda x: x % 2 == 0\r\nis_even(8) #True\r\n```\r\n\r\n- 求两个列表的交集\r\n```python\r\nintersection = list(set(list1) & set(list2))\r\n```\r\n\r\n- 从列表中删除重复项\r\n```python\r\nno_duplicates = list(set(my_list))\r\n```\r\n\r\n- 不使用 `len()` 计算字符串的长度\r\n```python\r\nlength = sum(1 for _ in \'Hello World\')\r\n```\r\n\r\n- 检查一个列表是否包含另一个列表的所有元素\r\n```python\r\ncontains_all = all(elem in list1 for elem in list2)\r\n```\r\n\r\n- 生成一串随机字符\r\n```python\r\nimport random; \r\nrandom_str = \'\'.join(random.choices(\'abcdefghijklmnopqrstuvwxyz\', k=10))\r\n```\r\n\r\n- 将整数列表转换为单个数字\r\n```python\r\nnum = int(\'\'.join(map(str, [1, 2, 3, 4, 5])))\r\n```\r\n\r\n- 回文(Palindromic)检查\r\n```python\r\nis_palindrome = lambda s: s == s[::-1]\r\n```\r\n\r\n- 列表展开\r\n```python\r\nflatten_list = sum([[1, 2], [3, 4]], [])\r\n```\r\n\r\n- 在一个列表中找到出现频率最高的元素\r\n```python\r\nmost_frequent = max(set(my_list), key=my_list.count)\r\n```\r\n\r\n- 合并两个字典\r\n```python\r\nmerged_dict = {**dict1, **dict2}\r\n```\r\n\r\n最后,我希望您喜欢阅读本文并有机会学习新东西。如果您有任何反馈,请随时在下面发表评论。如果您不想公开发表评论,可以随时给我发送电子邮件。我也很想看到你最喜欢的 python one liner 代码片段。', 'bodyText': 'Via:https://muhammadraza.me/2023/python-oneliners\n\n我已经沉浸在 Python 编程世界大约三年了。在这段时间里,我开始欣赏这种多功能语言的优雅和强大。在这篇既有趣又具有教育意义的文章中,我将展示一系列单行 Python 代码片段。无论您是经验丰富的开发人员还是初学者,这些简洁的代码行都可以让您深入了解 Python 的简单性和有效性,它们展示一行代码如何完成在其他语言中可能需要几行代码才能完成的任务。\n\n\n反转字符串\n\nreversed_string = "Hello World"[::-1]\n\n检查数字是否为偶数\n\nis_even = lambda x: x % 2 == 0\nis_even(8) #True\n\n求两个列表的交集\n\nintersection = list(set(list1) & set(list2))\n\n从列表中删除重复项\n\nno_duplicates = list(set(my_list))\n\n不使用 len() 计算字符串的长度\n\nlength = sum(1 for _ in \'Hello World\')\n\n检查一个列表是否包含另一个列表的所有元素\n\ncontains_all = all(elem in list1 for elem in list2)\n\n生成一串随机字符\n\nimport random; \nrandom_str = \'\'.join(random.choices(\'abcdefghijklmnopqrstuvwxyz\', k=10))\n\n将整数列表转换为单个数字\n\nnum = int(\'\'.join(map(str, [1, 2, 3, 4, 5])))\n\n回文(Palindromic)检查\n\nis_palindrome = lambda s: s == s[::-1]\n\n列表展开\n\nflatten_list = sum([[1, 2], [3, 4]], [])\n\n在一个列表中找到出现频率最高的元素\n\nmost_frequent = max(set(my_list), key=my_list.count)\n\n合并两个字典\n\nmerged_dict = {**dict1, **dict2}\n最后,我希望您喜欢阅读本文并有机会学习新东西。如果您有任何反馈,请随时在下面发表评论。如果您不想公开发表评论,可以随时给我发送电子邮件。我也很想看到你最喜欢的 python one liner 代码片段。', 'bodyHTML': '
\n

Via:https://muhammadraza.me/2023/python-oneliners

\n
\n

我已经沉浸在 Python 编程世界大约三年了。在这段时间里,我开始欣赏这种多功能语言的优雅和强大。在这篇既有趣又具有教育意义的文章中,我将展示一系列单行 Python 代码片段。无论您是经验丰富的开发人员还是初学者,这些简洁的代码行都可以让您深入了解 Python 的简单性和有效性,它们展示一行代码如何完成在其他语言中可能需要几行代码才能完成的任务。

\n\n
    \n
  • 反转字符串
  • \n
\n
reversed_string = "Hello World"[::-1]
\n
    \n
  • 检查数字是否为偶数
  • \n
\n
is_even = lambda x: x % 2 == 0\nis_even(8)  #True
\n
    \n
  • 求两个列表的交集
  • \n
\n
intersection = list(set(list1) & set(list2))
\n
    \n
  • 从列表中删除重复项
  • \n
\n
no_duplicates = list(set(my_list))
\n
    \n
  • 不使用 len() 计算字符串的长度
  • \n
\n
length = sum(1 for _ in \'Hello World\')
\n
    \n
  • 检查一个列表是否包含另一个列表的所有元素
  • \n
\n
contains_all = all(elem in list1 for elem in list2)
\n
    \n
  • 生成一串随机字符
  • \n
\n
import random; \nrandom_str = \'\'.join(random.choices(\'abcdefghijklmnopqrstuvwxyz\', k=10))
\n
    \n
  • 将整数列表转换为单个数字
  • \n
\n
num = int(\'\'.join(map(str, [1, 2, 3, 4, 5])))
\n
    \n
  • 回文(Palindromic)检查
  • \n
\n
is_palindrome = lambda s: s == s[::-1]
\n
    \n
  • 列表展开
  • \n
\n
flatten_list = sum([[1, 2], [3, 4]], [])
\n
    \n
  • 在一个列表中找到出现频率最高的元素
  • \n
\n
most_frequent = max(set(my_list), key=my_list.count)
\n
    \n
  • 合并两个字典
  • \n
\n
merged_dict = {**dict1, **dict2}
\n

最后,我希望您喜欢阅读本文并有机会学习新东西。如果您有任何反馈,请随时在下面发表评论。如果您不想公开发表评论,可以随时给我发送电子邮件。我也很想看到你最喜欢的 python one liner 代码片段。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.2-编程'}, 'labels': {'nodes': [{'name': '翻译'}, {'name': '1.2.3-Python'}]}, 'comments': {'nodes': []}}, {'title': '技术人月刊(第 1 期 2023-12)', 'number': 29, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/29', 'createdAt': '2023-12-01T02:57:46Z', 'lastEditedAt': '2023-12-20T03:32:00Z', 'updatedAt': '2023-12-20T03:32:00Z', 'body': '个人的信息周刊,每月记录我看到的有价值的信息,主要针对生物学和互联网科技领域,内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。\r\n\r\n## 工具\r\n\r\n1. [通过人工智能将表情符号变成令人惊叹的艺术品](https://github.com/leptonai/tryemoji)\r\n\r\n

\r\n\r\nGitHub 上的一个开源项目,包括了完整的前端和后端代码,支持本地和云端部署,可用于商业用途。\r\n\r\n2. [pdf2htmlEX](https://github.com/pdf2htmlEX/pdf2htmlEX)\r\n\r\n

\r\n

\r\n\r\n一个 PDF 转 HTML 程序,生成的结果和原始 PDF 几乎一模一样。其背后是利用的 Chrome Headless,让 Chrome 渲染 PDF,再导出成 HTML,甚至图片都转成了 base64 字符,所以一个网页就可以包含完整的文本、字体和图片等内容。\r\n\r\n3. [Quartz](https://github.com/jackyzha0/quartz)\r\n\r\nQuartz 是一套可帮助您免费将数字花园和笔记发布为网站的工具。Quartz v4 进行了彻底重写,重点关注最终用户的可扩展性和易用性。该工具可直接把 obsidian 笔记部署到线上,可以认为是 Obsidian Publish 功能的替代品,但是是免费的。不仅是 Obsidian 笔记,任何 markdown 双链笔记都可以部署。\r\n\r\n4. [gkd](https://github.com/gkd-kit/gkd)\r\n\r\n李跳跳被禁用后的一个替代品,基于高级选择器 + 订阅规则 + 快照审查,它可以实现点击跳过任意开屏广告/点击关闭应用内部任意弹窗广告, 如关闭百度贴吧帖子广告卡片/知乎回答底部推荐广告卡片。\r\n\r\n5. [Blossom](https://github.com/blossom-editor/blossom)\r\n\r\nBlossom 是一个支持私有部署的云端存储双链笔记软件,你可以将你所有的笔记,图片,个人计划安排保存在自己的服务器中,并在任意设备之间实时同步,且基于MIT协议完全开源。UI 非常漂亮的一款云端双链笔记。 \r\n\r\n\r\n6. [MDX Editor](https://editor.runjs.cool/) - 跨平台微信排版Markdown编辑器\r\n\r\nmdx 是 markdown + jsx 的结合,即可以支持 markdown 语法也可以写自定义组件。\r\n\r\n支持一键复制到微信公众号、自定义样式组件,样式、生成二维码、代码 diff 高亮、生成文章,软件还支持本地文件实时保存、文件目录树管理和导出 HTML。 \r\n![mdx-editor](https://shub.weiyan.tech/kgarden/2023/mdx-editor.png)\r\n\r\n## 文章\r\n\r\n1. [Cloudflare 发布了 2023 年度回顾](https://blog.cloudflare.com/radar-2023-year-in-review/)\r\n\r\n2023 年 Cloudflare Radar [#YearInReview](https://twitter.com/hashtag/YearInReview?src=hashtag_click) 是 Cloudflare 对全年在全球和国家/地区层面观察到的各种流量、连接性和速度指标的互联网趋势和模式的第四次年度回顾。\r\n\r\n## 资源\r\n\r\n1. [你用 Python 做过的最酷的事情是什么?](https://www.reddit.com/r/Python/comments/17upt2f/whats_the_coolest_things_youve_done_with_python/)\r\n\r\nreddit 上很火的一个讨论,让人大开眼界。\r\n\r\n3. [Data Hacks](https://data-hacks.com/)\r\n\r\n一个关于如何处理数据的网站,其中包含 1000 个快速 R 和 Python 教程。在这个网站上,您将会找到关于数据科学和统计学领域各种主题的 R 编程和 Python 编程指南。\r\n\r\n4. [哪个是程序员最爱的编程字体?2百万阅读的帖子选出最帅的七种字体](https://vikingz.me/best-font/)\r\n\r\n最后根据评论选出几款最受欢迎的供大家参考:Consolas,最多人推荐;JetBrains Mono 更推荐它的魔改版本 Jetbrains Mono Nerd Font;SF Mono,同样也有魔改版本 SFMono Nerd Font Ligaturized。\r\n\r\n5. [大规模语言模型:从理论到实践](https://intro-llm.github.io/)\r\n\r\n复旦大学张奇教授团队写的一本在线免费的电子书,《大规模语言模型:从理论到实践》,大概有 300 页篇幅,将大模型从理论到实战的每个阶段都描述的较为清楚。\r\n\r\n6. 《[Python 工匠](https://github.com/piglei/one-python-craftsman)》\r\n\r\n它专注于分享 Python 编程中的一些偏「小」的东西,例如变量和注释的使用、编写条件分支的技巧、编写跑的更快扩展性更好的代码,让函数反馈结果的技巧、异常处理的好习惯、装饰器的使用技巧等等。\r\n

one-python-craftsman

\r\n\r\n7. 《[Python Cookbook in Chinese](https://python3-cookbook.readthedocs.io/zh-cn/latest/index.html)》 3rd Edition\r\n

\r\n\r\n## 图片\r\n\r\n1. [世界上 14 座最伟大的宗教建筑](https://twitter.com/culturaltutor/status/1728746068324631017)\r\n\r\n来源于推特的信息,对于排名和入选不少网友表示怀疑,但的确很震撼。\r\n\r\n一. 日本京都金阁寺\r\n\r\n金阁寺(“金阁寺”)曾经是邪恶幕府将军的私人住宅,后来被他的儿子改建为禅宗佛教寺庙。 \r\n那是600年前的事了。它在 20 世纪 50 年代被一位和尚烧毁,并逐梁重建。\r\n\r\n\r\n二. 英国达勒姆大教堂\r\n\r\n英国最精美的诺曼大教堂,以其巨大的 11 世纪鼓柱和坚固的塔楼仍然占据着达勒姆市的主导地位。 \r\n现在它和一千年前一样庞大,仍然是卡斯伯特和贝德坟墓的所在地。 \r\n\r\n\r\n\r\n三. 哈尔格林姆教堂,雷克雅未克,冰岛\r\n\r\n世界上最伟大的现代主义教堂之一,将哥特式原则融入现代混凝土和钢材材料中。 \r\n一个富有表现力、迷人、近乎神奇的传统与现代结合的象征。 \r\n\r\n\r\n四. 印度北阿坎德邦 Gurdwara Sri Hemkund Sahib\r\n\r\n有时,让一座建筑变得如此非凡的不仅仅是建筑,还有它的位置。 \r\n位于喜马拉雅山 Garhwal 近 5,000 米高的 Gurdwara Sri Hemkund Sahib 也是如此。 \r\n\r\n\r\n\r\n\r\n五. 匈牙利塞格德犹太教堂\r\n\r\n这是一件不拘一格的杰作,由 Lipót Baumhorn 于 1902 年设计,充满了彩色玻璃和锻铁。 \r\n新艺术风格、新哥特式、新罗马式和新摩尔式建筑融合成一个建筑仙境。 \r\n\r\n\r\n\r\n\r\n六. 迪尔瓦拉耆那教寺庙,印度拉贾斯坦邦\r\n\r\n这座寺庙建于 11 世纪至 16 世纪,历时五百年,也许是索兰基风格建筑的最佳典范。 \r\n精心雕刻的雪白大理石的聚宝盆。 \r\n\r\n\r\n\r\n\r\n七. 保加利亚索非亚亚历山大涅夫斯基大教堂\r\n\r\n一座新拜占庭式建筑的纪念碑,经过三十年的建造,也许是保加利亚脱离奥斯曼帝国独立的顶峰。 \r\n外面有金色和绿色的圆顶瀑布;里面有一个阴暗的洞穴,里面有蜡烛和图标。 \r\n\r\n\r\n八. 叙利亚大马士革大清真寺\r\n\r\n世界上最伟大的建筑之一。这座拥有 4,000 年历史的礼拜场所,在这座从倭马亚王朝到奥斯曼帝国一次又一次改建的杰作的金色马赛克中,仍能看到腓尼基、罗马和早期基督教的遗迹。\r\n\r\n\r\n\r\n\r\n\r\n九. 希腊德尔斐阿波罗神庙\r\n\r\n曾经是古代世界最神圣的地方之一,是德尔斐神谕的故乡,也是所有希腊人的圣地。 \r\n尽管这座寺庙现已成为废墟,但其独特的神秘色彩依然存在,它拥有近 3,000 年的历史,位于帕纳苏斯山的高处。 \r\n\r\n\r\n十. 阿布辛贝,埃及\r\n\r\n一座古埃及神庙,由法老拉美西斯二世建造,旨在荣耀法老拉美西斯二世,成为尼罗河上神一般的永恒哨兵。 \r\n它在沙子下消失了两千多年,被挖掘出来,然后在建造阿斯旺大坝时,一块一块地移动。 \r\n\r\n\r\n\r\n\r\n十一. 科特迪瓦亚穆苏克罗和平圣母大教堂\r\n\r\n一座建于 20 世纪 80 年代的大教堂,令人难以置信。它的灵感来自罗马圣彼得大教堂,但并非直接模仿。据一些人说,它是世界上最大的教堂。 \r\n\r\n\r\n十二. 帕拉蒂纳无伴奏合唱团,巴勒莫,西西里岛\r\n\r\n许多建筑都被认为是独一无二的——这座建筑确实如此。前所未有的拜占庭式、诺曼式和法蒂玛式建筑矩阵;三种宗教和三种风格的结合。穆卡纳斯、半圆顶、圣像、圆形和尖形拱门……独一无二。 \r\n\r\n\r\n\r\n\r\n十三. 贵州梵净山寺庙,中国\r\n\r\n这两座佛教寺庙坐落在武陵山脉深处的岩石上,其历史可以追溯到几个世纪前,看起来几乎是不可能的。 \r\n但它们是真实存在的 — 它们的瓦片由于极端的风力而采用了铁质制作! \r\n\r\n\r\n十四. 印度泰米尔纳德邦米纳克希神庙\r\n\r\n这座庞大的建筑群有着悠久的历史,可以追溯到 1,000 多年前。它是德拉威建筑的一个令人惊叹的典范,拥有 14 座门楼(仪式性入口塔楼),其中一些具有纪念意义,覆盖着精美的彩色雕塑。 \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n', 'bodyText': '个人的信息周刊,每月记录我看到的有价值的信息,主要针对生物学和互联网科技领域,内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。\n工具\n\n通过人工智能将表情符号变成令人惊叹的艺术品\n\n\nGitHub 上的一个开源项目,包括了完整的前端和后端代码,支持本地和云端部署,可用于商业用途。\n\npdf2htmlEX\n\n\n\n一个 PDF 转 HTML 程序,生成的结果和原始 PDF 几乎一模一样。其背后是利用的 Chrome Headless,让 Chrome 渲染 PDF,再导出成 HTML,甚至图片都转成了 base64 字符,所以一个网页就可以包含完整的文本、字体和图片等内容。\n\nQuartz\n\nQuartz 是一套可帮助您免费将数字花园和笔记发布为网站的工具。Quartz v4 进行了彻底重写,重点关注最终用户的可扩展性和易用性。该工具可直接把 obsidian 笔记部署到线上,可以认为是 Obsidian Publish 功能的替代品,但是是免费的。不仅是 Obsidian 笔记,任何 markdown 双链笔记都可以部署。\n\ngkd\n\n李跳跳被禁用后的一个替代品,基于高级选择器 + 订阅规则 + 快照审查,它可以实现点击跳过任意开屏广告/点击关闭应用内部任意弹窗广告, 如关闭百度贴吧帖子广告卡片/知乎回答底部推荐广告卡片。\n\nBlossom\n\nBlossom 是一个支持私有部署的云端存储双链笔记软件,你可以将你所有的笔记,图片,个人计划安排保存在自己的服务器中,并在任意设备之间实时同步,且基于MIT协议完全开源。UI 非常漂亮的一款云端双链笔记。\n\n\nMDX Editor - 跨平台微信排版Markdown编辑器\n\nmdx 是 markdown + jsx 的结合,即可以支持 markdown 语法也可以写自定义组件。\n支持一键复制到微信公众号、自定义样式组件,样式、生成二维码、代码 diff 高亮、生成文章,软件还支持本地文件实时保存、文件目录树管理和导出 HTML。\n\n文章\n\nCloudflare 发布了 2023 年度回顾\n\n2023 年 Cloudflare Radar #YearInReview 是 Cloudflare 对全年在全球和国家/地区层面观察到的各种流量、连接性和速度指标的互联网趋势和模式的第四次年度回顾。\n资源\n\n你用 Python 做过的最酷的事情是什么?\n\nreddit 上很火的一个讨论,让人大开眼界。\n\nData Hacks\n\n一个关于如何处理数据的网站,其中包含 1000 个快速 R 和 Python 教程。在这个网站上,您将会找到关于数据科学和统计学领域各种主题的 R 编程和 Python 编程指南。\n\n哪个是程序员最爱的编程字体?2百万阅读的帖子选出最帅的七种字体\n\n最后根据评论选出几款最受欢迎的供大家参考:Consolas,最多人推荐;JetBrains Mono 更推荐它的魔改版本 Jetbrains Mono Nerd Font;SF Mono,同样也有魔改版本 SFMono Nerd Font Ligaturized。\n\n大规模语言模型:从理论到实践\n\n复旦大学张奇教授团队写的一本在线免费的电子书,《大规模语言模型:从理论到实践》,大概有 300 页篇幅,将大模型从理论到实战的每个阶段都描述的较为清楚。\n\n《Python 工匠》\n\n它专注于分享 Python 编程中的一些偏「小」的东西,例如变量和注释的使用、编写条件分支的技巧、编写跑的更快扩展性更好的代码,让函数反馈结果的技巧、异常处理的好习惯、装饰器的使用技巧等等。\n\n\n《Python Cookbook in Chinese》 3rd Edition\n\n\n图片\n\n世界上 14 座最伟大的宗教建筑\n\n来源于推特的信息,对于排名和入选不少网友表示怀疑,但的确很震撼。\n一. 日本京都金阁寺\n金阁寺(“金阁寺”)曾经是邪恶幕府将军的私人住宅,后来被他的儿子改建为禅宗佛教寺庙。\n那是600年前的事了。它在 20 世纪 50 年代被一位和尚烧毁,并逐梁重建。\n\n二. 英国达勒姆大教堂\n英国最精美的诺曼大教堂,以其巨大的 11 世纪鼓柱和坚固的塔楼仍然占据着达勒姆市的主导地位。\n现在它和一千年前一样庞大,仍然是卡斯伯特和贝德坟墓的所在地。\n\n\n三. 哈尔格林姆教堂,雷克雅未克,冰岛\n世界上最伟大的现代主义教堂之一,将哥特式原则融入现代混凝土和钢材材料中。\n一个富有表现力、迷人、近乎神奇的传统与现代结合的象征。\n\n四. 印度北阿坎德邦 Gurdwara Sri Hemkund Sahib\n有时,让一座建筑变得如此非凡的不仅仅是建筑,还有它的位置。\n位于喜马拉雅山 Garhwal 近 5,000 米高的 Gurdwara Sri Hemkund Sahib 也是如此。\n\n\n\n五. 匈牙利塞格德犹太教堂\n这是一件不拘一格的杰作,由 Lipót Baumhorn 于 1902 年设计,充满了彩色玻璃和锻铁。\n新艺术风格、新哥特式、新罗马式和新摩尔式建筑融合成一个建筑仙境。\n\n\n\n六. 迪尔瓦拉耆那教寺庙,印度拉贾斯坦邦\n这座寺庙建于 11 世纪至 16 世纪,历时五百年,也许是索兰基风格建筑的最佳典范。\n精心雕刻的雪白大理石的聚宝盆。\n\n\n\n七. 保加利亚索非亚亚历山大涅夫斯基大教堂\n一座新拜占庭式建筑的纪念碑,经过三十年的建造,也许是保加利亚脱离奥斯曼帝国独立的顶峰。\n外面有金色和绿色的圆顶瀑布;里面有一个阴暗的洞穴,里面有蜡烛和图标。\n\n八. 叙利亚大马士革大清真寺\n世界上最伟大的建筑之一。这座拥有 4,000 年历史的礼拜场所,在这座从倭马亚王朝到奥斯曼帝国一次又一次改建的杰作的金色马赛克中,仍能看到腓尼基、罗马和早期基督教的遗迹。\n\n\n\n\n九. 希腊德尔斐阿波罗神庙\n曾经是古代世界最神圣的地方之一,是德尔斐神谕的故乡,也是所有希腊人的圣地。\n尽管这座寺庙现已成为废墟,但其独特的神秘色彩依然存在,它拥有近 3,000 年的历史,位于帕纳苏斯山的高处。\n\n十. 阿布辛贝,埃及\n一座古埃及神庙,由法老拉美西斯二世建造,旨在荣耀法老拉美西斯二世,成为尼罗河上神一般的永恒哨兵。\n它在沙子下消失了两千多年,被挖掘出来,然后在建造阿斯旺大坝时,一块一块地移动。\n\n\n\n十一. 科特迪瓦亚穆苏克罗和平圣母大教堂\n一座建于 20 世纪 80 年代的大教堂,令人难以置信。它的灵感来自罗马圣彼得大教堂,但并非直接模仿。据一些人说,它是世界上最大的教堂。\n\n十二. 帕拉蒂纳无伴奏合唱团,巴勒莫,西西里岛\n许多建筑都被认为是独一无二的——这座建筑确实如此。前所未有的拜占庭式、诺曼式和法蒂玛式建筑矩阵;三种宗教和三种风格的结合。穆卡纳斯、半圆顶、圣像、圆形和尖形拱门……独一无二。\n\n\n\n十三. 贵州梵净山寺庙,中国\n这两座佛教寺庙坐落在武陵山脉深处的岩石上,其历史可以追溯到几个世纪前,看起来几乎是不可能的。\n但它们是真实存在的 — 它们的瓦片由于极端的风力而采用了铁质制作!\n\n十四. 印度泰米尔纳德邦米纳克希神庙\n这座庞大的建筑群有着悠久的历史,可以追溯到 1,000 多年前。它是德拉威建筑的一个令人惊叹的典范,拥有 14 座门楼(仪式性入口塔楼),其中一些具有纪念意义,覆盖着精美的彩色雕塑。', 'bodyHTML': '

个人的信息周刊,每月记录我看到的有价值的信息,主要针对生物学和互联网科技领域,内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。

\n

工具

\n
    \n
  1. 通过人工智能将表情符号变成令人惊叹的艺术品
  2. \n
\n

\n

GitHub 上的一个开源项目,包括了完整的前端和后端代码,支持本地和云端部署,可用于商业用途。

\n
    \n
  1. pdf2htmlEX
  2. \n
\n

\n

\n

一个 PDF 转 HTML 程序,生成的结果和原始 PDF 几乎一模一样。其背后是利用的 Chrome Headless,让 Chrome 渲染 PDF,再导出成 HTML,甚至图片都转成了 base64 字符,所以一个网页就可以包含完整的文本、字体和图片等内容。

\n
    \n
  1. Quartz
  2. \n
\n

Quartz 是一套可帮助您免费将数字花园和笔记发布为网站的工具。Quartz v4 进行了彻底重写,重点关注最终用户的可扩展性和易用性。该工具可直接把 obsidian 笔记部署到线上,可以认为是 Obsidian Publish 功能的替代品,但是是免费的。不仅是 Obsidian 笔记,任何 markdown 双链笔记都可以部署。

\n
    \n
  1. gkd
  2. \n
\n

李跳跳被禁用后的一个替代品,基于高级选择器 + 订阅规则 + 快照审查,它可以实现点击跳过任意开屏广告/点击关闭应用内部任意弹窗广告, 如关闭百度贴吧帖子广告卡片/知乎回答底部推荐广告卡片。

\n
    \n
  1. Blossom
  2. \n
\n

Blossom 是一个支持私有部署的云端存储双链笔记软件,你可以将你所有的笔记,图片,个人计划安排保存在自己的服务器中,并在任意设备之间实时同步,且基于MIT协议完全开源。UI 非常漂亮的一款云端双链笔记。
\n

\n
    \n
  1. MDX Editor - 跨平台微信排版Markdown编辑器
  2. \n
\n

mdx 是 markdown + jsx 的结合,即可以支持 markdown 语法也可以写自定义组件。

\n

支持一键复制到微信公众号、自定义样式组件,样式、生成二维码、代码 diff 高亮、生成文章,软件还支持本地文件实时保存、文件目录树管理和导出 HTML。
\nmdx-editor

\n

文章

\n
    \n
  1. Cloudflare 发布了 2023 年度回顾
  2. \n
\n

2023 年 Cloudflare Radar #YearInReview 是 Cloudflare 对全年在全球和国家/地区层面观察到的各种流量、连接性和速度指标的互联网趋势和模式的第四次年度回顾。

\n

资源

\n
    \n
  1. 你用 Python 做过的最酷的事情是什么?
  2. \n
\n

reddit 上很火的一个讨论,让人大开眼界。

\n
    \n
  1. Data Hacks
  2. \n
\n

一个关于如何处理数据的网站,其中包含 1000 个快速 R 和 Python 教程。在这个网站上,您将会找到关于数据科学和统计学领域各种主题的 R 编程和 Python 编程指南。

\n
    \n
  1. 哪个是程序员最爱的编程字体?2百万阅读的帖子选出最帅的七种字体
  2. \n
\n

最后根据评论选出几款最受欢迎的供大家参考:Consolas,最多人推荐;JetBrains Mono 更推荐它的魔改版本 Jetbrains Mono Nerd Font;SF Mono,同样也有魔改版本 SFMono Nerd Font Ligaturized。

\n
    \n
  1. 大规模语言模型:从理论到实践
  2. \n
\n

复旦大学张奇教授团队写的一本在线免费的电子书,《大规模语言模型:从理论到实践》,大概有 300 页篇幅,将大模型从理论到实战的每个阶段都描述的较为清楚。

\n
    \n
  1. Python 工匠
  2. \n
\n

它专注于分享 Python 编程中的一些偏「小」的东西,例如变量和注释的使用、编写条件分支的技巧、编写跑的更快扩展性更好的代码,让函数反馈结果的技巧、异常处理的好习惯、装饰器的使用技巧等等。

\n

one-python-craftsman

\n
    \n
  1. Python Cookbook in Chinese》 3rd Edition
  2. \n
\n

\n

图片

\n
    \n
  1. 世界上 14 座最伟大的宗教建筑
  2. \n
\n

来源于推特的信息,对于排名和入选不少网友表示怀疑,但的确很震撼。

\n

一. 日本京都金阁寺

\n

金阁寺(“金阁寺”)曾经是邪恶幕府将军的私人住宅,后来被他的儿子改建为禅宗佛教寺庙。
\n那是600年前的事了。它在 20 世纪 50 年代被一位和尚烧毁,并逐梁重建。
\n

\n

二. 英国达勒姆大教堂

\n

英国最精美的诺曼大教堂,以其巨大的 11 世纪鼓柱和坚固的塔楼仍然占据着达勒姆市的主导地位。
\n现在它和一千年前一样庞大,仍然是卡斯伯特和贝德坟墓的所在地。
\n
\n

\n

三. 哈尔格林姆教堂,雷克雅未克,冰岛

\n

世界上最伟大的现代主义教堂之一,将哥特式原则融入现代混凝土和钢材材料中。
\n一个富有表现力、迷人、近乎神奇的传统与现代结合的象征。
\n

\n

四. 印度北阿坎德邦 Gurdwara Sri Hemkund Sahib

\n

有时,让一座建筑变得如此非凡的不仅仅是建筑,还有它的位置。
\n位于喜马拉雅山 Garhwal 近 5,000 米高的 Gurdwara Sri Hemkund Sahib 也是如此。
\n
\n
\n

\n

五. 匈牙利塞格德犹太教堂

\n

这是一件不拘一格的杰作,由 Lipót Baumhorn 于 1902 年设计,充满了彩色玻璃和锻铁。
\n新艺术风格、新哥特式、新罗马式和新摩尔式建筑融合成一个建筑仙境。
\n
\n
\n

\n

六. 迪尔瓦拉耆那教寺庙,印度拉贾斯坦邦

\n

这座寺庙建于 11 世纪至 16 世纪,历时五百年,也许是索兰基风格建筑的最佳典范。
\n精心雕刻的雪白大理石的聚宝盆。
\n
\n
\n

\n

七. 保加利亚索非亚亚历山大涅夫斯基大教堂

\n

一座新拜占庭式建筑的纪念碑,经过三十年的建造,也许是保加利亚脱离奥斯曼帝国独立的顶峰。
\n外面有金色和绿色的圆顶瀑布;里面有一个阴暗的洞穴,里面有蜡烛和图标。
\n

\n

八. 叙利亚大马士革大清真寺

\n

世界上最伟大的建筑之一。这座拥有 4,000 年历史的礼拜场所,在这座从倭马亚王朝到奥斯曼帝国一次又一次改建的杰作的金色马赛克中,仍能看到腓尼基、罗马和早期基督教的遗迹。
\n
\n
\n
\n

\n

九. 希腊德尔斐阿波罗神庙

\n

曾经是古代世界最神圣的地方之一,是德尔斐神谕的故乡,也是所有希腊人的圣地。
\n尽管这座寺庙现已成为废墟,但其独特的神秘色彩依然存在,它拥有近 3,000 年的历史,位于帕纳苏斯山的高处。
\n

\n

十. 阿布辛贝,埃及

\n

一座古埃及神庙,由法老拉美西斯二世建造,旨在荣耀法老拉美西斯二世,成为尼罗河上神一般的永恒哨兵。
\n它在沙子下消失了两千多年,被挖掘出来,然后在建造阿斯旺大坝时,一块一块地移动。
\n
\n
\n

\n

十一. 科特迪瓦亚穆苏克罗和平圣母大教堂

\n

一座建于 20 世纪 80 年代的大教堂,令人难以置信。它的灵感来自罗马圣彼得大教堂,但并非直接模仿。据一些人说,它是世界上最大的教堂。
\n

\n

十二. 帕拉蒂纳无伴奏合唱团,巴勒莫,西西里岛

\n

许多建筑都被认为是独一无二的——这座建筑确实如此。前所未有的拜占庭式、诺曼式和法蒂玛式建筑矩阵;三种宗教和三种风格的结合。穆卡纳斯、半圆顶、圣像、圆形和尖形拱门……独一无二。
\n
\n
\n

\n

十三. 贵州梵净山寺庙,中国

\n

这两座佛教寺庙坐落在武陵山脉深处的岩石上,其历史可以追溯到几个世纪前,看起来几乎是不可能的。
\n但它们是真实存在的 — 它们的瓦片由于极端的风力而采用了铁质制作!
\n

\n

十四. 印度泰米尔纳德邦米纳克希神庙

\n

这座庞大的建筑群有着悠久的历史,可以追溯到 1,000 多年前。它是德拉威建筑的一个令人惊叹的典范,拥有 14 座门楼(仪式性入口塔楼),其中一些具有纪念意义,覆盖着精美的彩色雕塑。
\n
\n
\n

', 'author': {'login': 'shenweiyan'}, 'category': {'name': 'x.2-月刊'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '公众号许久没有更新了', 'number': 28, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/28', 'createdAt': '2023-12-01T02:36:37Z', 'lastEditedAt': '2023-12-08T05:34:13Z', 'updatedAt': '2023-12-08T05:34:13Z', 'body': '大家可能会发现自从 2023 年下半年以来,**"BioIT 爱好者"** 公众号的更新频率越来越低了。\r\n\r\n这里面除了个人私人时间越来越少以外,还有一个原因就是个人把写文章从语雀转移到了 [GitHub](https://github.com/shenweiyan/) 的 Issues 和 Discussions 上。\r\n\r\n\r\n\r\n虽然在很长一段时间以来,个人一直都在使用 [语雀](https://www.yuque.com/shenweiyan) 来记录个人工作、生活的各种知识,但直到今年的下半年在考虑数据多平台使用+备份+搜索的一些使用场景时才发现语雀无法批量导出的一些弊端,更重要的一个原因是正如在 "[博客与写作的一些思考](https://github.com/shenweiyan/Knowledge-Garden/issues/34)" 里面所提到的 **"博客其实就是写给自己看的"**,**"大部分人写所谓 \'博客\' 到最后都把时间花在装潢 CSS HTML 主题上了"**!几经考虑以后,选择了 [GitHub](https://github.com/shenweiyan/) 的 Issues 和 Discussions,对于其中的优点:\r\n\r\n- 全免费,不需要租用域名和服务器;\r\n- 不需要过多折腾,对不懂技术的人来说非常友好;\r\n- Issues/Discussions 自带评论功能,不需要后期为博客安装评论插件;\r\n- GitHub 有网页版和手机 App,只要有网,我们可以随时随地发布文章,而不仅仅局限于电脑;\r\n- 发布到 GitHub 的内容,在 Google 的搜索结果中有非常高的权重;\r\n- 回归 CommonMark 的编辑,方便各种支持 Markdown 平台间的备份迁移;\r\n- 借助 GitHub REST/GraphQL API 可以很方便实现 Issues/Discussions 的导入导出;\r\n- 借助 GitHub Pages 和 GitHub Actions,可以轻松把 Issues/Discussions 转化成静态博客\r\n\r\n借助一些开源的工具,个人目前大部分文章都已经从语 [语雀](https://www.yuque.com/shenweiyan) 同步到了 [shenweiyan/Knowledge-Garden](https://github.com/shenweiyan/Knowledge-Garden),并后续会继续在 GitHub 进行更新,由于[公众号的各种限制和封闭性](https://www.yuque.com/shenweiyan/articles/qw325a),如精力和时间允许后续会同步至公众号。\r\n\r\n![Knowledge-Garden Repo image](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/github-knowledge-garden.png)\r\n\r\n![Knowledge-Garden Discussions image](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/knowledge-garden-discussions.png)\r\n', 'bodyText': '大家可能会发现自从 2023 年下半年以来,"BioIT 爱好者" 公众号的更新频率越来越低了。\n这里面除了个人私人时间越来越少以外,还有一个原因就是个人把写文章从语雀转移到了 GitHub 的 Issues 和 Discussions 上。\n\n虽然在很长一段时间以来,个人一直都在使用 语雀 来记录个人工作、生活的各种知识,但直到今年的下半年在考虑数据多平台使用+备份+搜索的一些使用场景时才发现语雀无法批量导出的一些弊端,更重要的一个原因是正如在 "博客与写作的一些思考" 里面所提到的 "博客其实就是写给自己看的","大部分人写所谓 \'博客\' 到最后都把时间花在装潢 CSS HTML 主题上了"!几经考虑以后,选择了 GitHub 的 Issues 和 Discussions,对于其中的优点:\n\n全免费,不需要租用域名和服务器;\n不需要过多折腾,对不懂技术的人来说非常友好;\nIssues/Discussions 自带评论功能,不需要后期为博客安装评论插件;\nGitHub 有网页版和手机 App,只要有网,我们可以随时随地发布文章,而不仅仅局限于电脑;\n发布到 GitHub 的内容,在 Google 的搜索结果中有非常高的权重;\n回归 CommonMark 的编辑,方便各种支持 Markdown 平台间的备份迁移;\n借助 GitHub REST/GraphQL API 可以很方便实现 Issues/Discussions 的导入导出;\n借助 GitHub Pages 和 GitHub Actions,可以轻松把 Issues/Discussions 转化成静态博客\n\n借助一些开源的工具,个人目前大部分文章都已经从语 语雀 同步到了 shenweiyan/Knowledge-Garden,并后续会继续在 GitHub 进行更新,由于公众号的各种限制和封闭性,如精力和时间允许后续会同步至公众号。', 'bodyHTML': '

大家可能会发现自从 2023 年下半年以来,"BioIT 爱好者" 公众号的更新频率越来越低了。

\n

这里面除了个人私人时间越来越少以外,还有一个原因就是个人把写文章从语雀转移到了 GitHub 的 Issues 和 Discussions 上。

\n\n

虽然在很长一段时间以来,个人一直都在使用 语雀 来记录个人工作、生活的各种知识,但直到今年的下半年在考虑数据多平台使用+备份+搜索的一些使用场景时才发现语雀无法批量导出的一些弊端,更重要的一个原因是正如在 "博客与写作的一些思考" 里面所提到的 "博客其实就是写给自己看的""大部分人写所谓 \'博客\' 到最后都把时间花在装潢 CSS HTML 主题上了"!几经考虑以后,选择了 GitHub 的 Issues 和 Discussions,对于其中的优点:

\n
    \n
  • 全免费,不需要租用域名和服务器;
  • \n
  • 不需要过多折腾,对不懂技术的人来说非常友好;
  • \n
  • Issues/Discussions 自带评论功能,不需要后期为博客安装评论插件;
  • \n
  • GitHub 有网页版和手机 App,只要有网,我们可以随时随地发布文章,而不仅仅局限于电脑;
  • \n
  • 发布到 GitHub 的内容,在 Google 的搜索结果中有非常高的权重;
  • \n
  • 回归 CommonMark 的编辑,方便各种支持 Markdown 平台间的备份迁移;
  • \n
  • 借助 GitHub REST/GraphQL API 可以很方便实现 Issues/Discussions 的导入导出;
  • \n
  • 借助 GitHub Pages 和 GitHub Actions,可以轻松把 Issues/Discussions 转化成静态博客
  • \n
\n

借助一些开源的工具,个人目前大部分文章都已经从语 语雀 同步到了 shenweiyan/Knowledge-Garden,并后续会继续在 GitHub 进行更新,由于公众号的各种限制和封闭性,如精力和时间允许后续会同步至公众号。

\n

Knowledge-Garden Repo image

\n

Knowledge-Garden Discussions image

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': [{'name': '公众号'}]}, 'comments': {'nodes': []}}, {'title': 'Python3 编译安装 --with-openssl 无效的问题', 'number': 27, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/27', 'createdAt': '2023-12-01T02:32:24Z', 'lastEditedAt': None, 'updatedAt': '2024-01-03T07:57:48Z', 'body': '很多人在使用 Python3 经常会遇到一些 openssl 版本太低从而导致包无法正常使用的问题,尤其是 `urllib3` 这个包。\r\n```python\r\nPython 3.9.18 (main, Sep 7 2023, 14:32:17) \r\n[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux\r\nType "help", "copyright", "credits" or "license" for more information.\r\n>>> import requests\r\nTraceback (most recent call last):\r\n File "", line 1, in \r\n File "/usr/local/software/python-3.9.18/lib/python3.9/site-packages/requests/__init__.py", line 43, in \r\n import urllib3\r\n File "/usr/local/software/python-3.9.18/lib/python3.9/site-packages/urllib3/__init__.py", line 41, in \r\n raise ImportError(\r\nImportError: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the \'ssl\' module is compiled with \'OpenSSL 1.0.2k-fips 26 Jan 2017\'. See: https://github.com/urllib3/urllib3/issues/2168\r\n>>> import ssl\r\n>>> import urllib3\r\nTraceback (most recent call last):\r\n File "", line 1, in \r\n File "/usr/local/software/python-3.9.18/lib/python3.9/site-packages/urllib3/__init__.py", line 41, in \r\n raise ImportError(\r\nImportError: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the \'ssl\' module is compiled with \'OpenSSL 1.0.2k-fips 26 Jan 2017\'. See: https://github.com/urllib3/urllib3/issues/2168\r\n```\r\n\r\n网络上有很多关于这方面的教程,主要解决方案:\r\n\r\n1. 降级 `urllib3` 的版本,例如:`pip install --upgrade urllib3==1.26.15`;\r\n2. 重新安装一个更高版本的 OpenSSL,然后备份并替换系统原来的 openssl,最后重新编译安装 Python。\r\n\r\n个人觉得这两个方法都不够好,尤其是第二个方法 —— \r\n\r\n- 新装了一个更高版本的 OpenSSL,但是又不想替换系统原来的 openssl 以免出现新的问题(或者没有管理员权限);\r\n- 在编译的时候使用 `--with-openssl` 指定了新装的 OpenSSL 路径,编译安装完成后 Python **仍然使用旧版本的 OpenSSL**;\r\n\r\n很不幸的是,个人在 CentOS 7.3 + Python-3.9.18 就遇到了这个问题。\r\n\r\n1. 新装了 OpenSSL 3.0.10 \r\n```\r\nwget https://www.openssl.org/source/openssl-3.0.10.tar.gz --no-check-certificate\r\ntar zvxf openssl-3.0.10.tar.gz\r\ncd openssl-3.0.10\r\n./config --prefix=/usr/local/software/openssl-3.0.10 shared zlib\r\nmake && make install\r\n```\r\n\r\n2. 添加 `~/.bashrc` 环境变量\r\n```\r\nexport PATH=/usr/local/software/openssl-3.0.10/bin:$PATH\r\nexport LD_LIBRARY_PATH=/usr/local/software/openssl-3.0.10/lib64:$LD_LIBRARY_PATH\r\n```\r\n\r\n3. 重新编译安装 Python-3.9.18\r\n```\r\n./configure --prefix=/usr/local/software/python-3.9.18 --with-openssl=/usr/local/software/openssl-3.0.10/\r\nmake && make install\r\n```\r\n\r\n等编译完成后,你会神奇的发现重新编译安装后 Python 3.9.18 **仍然使用旧版本的 OpenSSL (OpenSSL 1.0.2k-fips 26 Jan 2017)**!\r\n\r\n其实,这还是因为 Python 在重新编译的时候没有识别到新编译的 OpenSSL,因此,我们需要把重新编译的命令调整一下:\r\n```\r\n/configure --prefix=/usr/local/software/python-3.9.18 \\\r\n--with-openssl=/usr/local/software/openssl-3.0.10/ \\\r\nLDFLAGS="-L/usr/local/software/openssl-3.0.10/lib64" \\\r\nCPPFLAGS="-I/usr/local/software/openssl-3.0.10/include" \\\r\nPKG_CONFIG_PATH="/usr/local/software/openssl-3.0.10/lib64/pkgconfig"\r\n```\r\n\r\n这样子一来,问题就迎刃而解了,编译安装完后,你会发现 Python 3.9.18 已经成功用用上了 OpenSSL 3.0.10 1 Aug 2023:\r\n```\r\n$ python3 -c "import ssl; print(ssl.OPENSSL_VERSION)"\r\nOpenSSL 3.0.10 1 Aug 2023\r\n```\r\n![OpenSSL 3.0.10 on Python3.9.18](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/Gitbook/2023/python-3.9.18-openssl-3.0.10.png)\r\n\r\n## 参考资料\r\n\r\n1. [Drop support for OpenSSL<1.1.1 - urllib3/urllib3#2168](https://github.com/urllib3/urllib3/issues/2168)\r\n\r\n', 'bodyText': '很多人在使用 Python3 经常会遇到一些 openssl 版本太低从而导致包无法正常使用的问题,尤其是 urllib3 这个包。\nPython 3.9.18 (main, Sep 7 2023, 14:32:17) \n[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux\nType "help", "copyright", "credits" or "license" for more information.\n>>> import requests\nTraceback (most recent call last):\n File "", line 1, in \n File "/usr/local/software/python-3.9.18/lib/python3.9/site-packages/requests/__init__.py", line 43, in \n import urllib3\n File "/usr/local/software/python-3.9.18/lib/python3.9/site-packages/urllib3/__init__.py", line 41, in \n raise ImportError(\nImportError: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the \'ssl\' module is compiled with \'OpenSSL 1.0.2k-fips 26 Jan 2017\'. See: https://github.com/urllib3/urllib3/issues/2168\n>>> import ssl\n>>> import urllib3\nTraceback (most recent call last):\n File "", line 1, in \n File "/usr/local/software/python-3.9.18/lib/python3.9/site-packages/urllib3/__init__.py", line 41, in \n raise ImportError(\nImportError: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the \'ssl\' module is compiled with \'OpenSSL 1.0.2k-fips 26 Jan 2017\'. See: https://github.com/urllib3/urllib3/issues/2168\n网络上有很多关于这方面的教程,主要解决方案:\n\n降级 urllib3 的版本,例如:pip install --upgrade urllib3==1.26.15;\n重新安装一个更高版本的 OpenSSL,然后备份并替换系统原来的 openssl,最后重新编译安装 Python。\n\n个人觉得这两个方法都不够好,尤其是第二个方法 ——\n\n新装了一个更高版本的 OpenSSL,但是又不想替换系统原来的 openssl 以免出现新的问题(或者没有管理员权限);\n在编译的时候使用 --with-openssl 指定了新装的 OpenSSL 路径,编译安装完成后 Python 仍然使用旧版本的 OpenSSL;\n\n很不幸的是,个人在 CentOS 7.3 + Python-3.9.18 就遇到了这个问题。\n\n新装了 OpenSSL 3.0.10\n\nwget https://www.openssl.org/source/openssl-3.0.10.tar.gz --no-check-certificate\ntar zvxf openssl-3.0.10.tar.gz\ncd openssl-3.0.10\n./config --prefix=/usr/local/software/openssl-3.0.10 shared zlib\nmake && make install\n\n\n添加 ~/.bashrc 环境变量\n\nexport PATH=/usr/local/software/openssl-3.0.10/bin:$PATH\nexport LD_LIBRARY_PATH=/usr/local/software/openssl-3.0.10/lib64:$LD_LIBRARY_PATH\n\n\n重新编译安装 Python-3.9.18\n\n./configure --prefix=/usr/local/software/python-3.9.18 --with-openssl=/usr/local/software/openssl-3.0.10/\nmake && make install\n\n等编译完成后,你会神奇的发现重新编译安装后 Python 3.9.18 仍然使用旧版本的 OpenSSL (OpenSSL 1.0.2k-fips 26 Jan 2017)!\n其实,这还是因为 Python 在重新编译的时候没有识别到新编译的 OpenSSL,因此,我们需要把重新编译的命令调整一下:\n/configure --prefix=/usr/local/software/python-3.9.18 \\\n--with-openssl=/usr/local/software/openssl-3.0.10/ \\\nLDFLAGS="-L/usr/local/software/openssl-3.0.10/lib64" \\\nCPPFLAGS="-I/usr/local/software/openssl-3.0.10/include" \\\nPKG_CONFIG_PATH="/usr/local/software/openssl-3.0.10/lib64/pkgconfig"\n\n这样子一来,问题就迎刃而解了,编译安装完后,你会发现 Python 3.9.18 已经成功用用上了 OpenSSL 3.0.10 1 Aug 2023:\n$ python3 -c "import ssl; print(ssl.OPENSSL_VERSION)"\nOpenSSL 3.0.10 1 Aug 2023\n\n\n参考资料\n\nDrop support for OpenSSL<1.1.1 - urllib3/urllib3#2168', 'bodyHTML': '

很多人在使用 Python3 经常会遇到一些 openssl 版本太低从而导致包无法正常使用的问题,尤其是 urllib3 这个包。

\n
Python 3.9.18 (main, Sep  7 2023, 14:32:17) \n[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux\nType "help", "copyright", "credits" or "license" for more information.\n>>> import requests\nTraceback (most recent call last):\n  File "<stdin>", line 1, in <module>\n  File "/usr/local/software/python-3.9.18/lib/python3.9/site-packages/requests/__init__.py", line 43, in <module>\n    import urllib3\n  File "/usr/local/software/python-3.9.18/lib/python3.9/site-packages/urllib3/__init__.py", line 41, in <module>\n    raise ImportError(\nImportError: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the \'ssl\' module is compiled with \'OpenSSL 1.0.2k-fips  26 Jan 2017\'. See: https://github.com/urllib3/urllib3/issues/2168\n>>> import ssl\n>>> import urllib3\nTraceback (most recent call last):\n  File "<stdin>", line 1, in <module>\n  File "/usr/local/software/python-3.9.18/lib/python3.9/site-packages/urllib3/__init__.py", line 41, in <module>\n    raise ImportError(\nImportError: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the \'ssl\' module is compiled with \'OpenSSL 1.0.2k-fips  26 Jan 2017\'. See: https://github.com/urllib3/urllib3/issues/2168
\n

网络上有很多关于这方面的教程,主要解决方案:

\n
    \n
  1. 降级 urllib3 的版本,例如:pip install --upgrade urllib3==1.26.15
  2. \n
  3. 重新安装一个更高版本的 OpenSSL,然后备份并替换系统原来的 openssl,最后重新编译安装 Python。
  4. \n
\n

个人觉得这两个方法都不够好,尤其是第二个方法 ——

\n
    \n
  • 新装了一个更高版本的 OpenSSL,但是又不想替换系统原来的 openssl 以免出现新的问题(或者没有管理员权限);
  • \n
  • 在编译的时候使用 --with-openssl 指定了新装的 OpenSSL 路径,编译安装完成后 Python 仍然使用旧版本的 OpenSSL
  • \n
\n

很不幸的是,个人在 CentOS 7.3 + Python-3.9.18 就遇到了这个问题。

\n
    \n
  1. 新装了 OpenSSL 3.0.10
  2. \n
\n
wget https://www.openssl.org/source/openssl-3.0.10.tar.gz --no-check-certificate\ntar zvxf openssl-3.0.10.tar.gz\ncd openssl-3.0.10\n./config --prefix=/usr/local/software/openssl-3.0.10 shared zlib\nmake && make install\n
\n
    \n
  1. 添加 ~/.bashrc 环境变量
  2. \n
\n
export PATH=/usr/local/software/openssl-3.0.10/bin:$PATH\nexport LD_LIBRARY_PATH=/usr/local/software/openssl-3.0.10/lib64:$LD_LIBRARY_PATH\n
\n
    \n
  1. 重新编译安装 Python-3.9.18
  2. \n
\n
./configure --prefix=/usr/local/software/python-3.9.18 --with-openssl=/usr/local/software/openssl-3.0.10/\nmake && make install\n
\n

等编译完成后,你会神奇的发现重新编译安装后 Python 3.9.18 仍然使用旧版本的 OpenSSL (OpenSSL 1.0.2k-fips 26 Jan 2017)

\n

其实,这还是因为 Python 在重新编译的时候没有识别到新编译的 OpenSSL,因此,我们需要把重新编译的命令调整一下:

\n
/configure --prefix=/usr/local/software/python-3.9.18 \\\n--with-openssl=/usr/local/software/openssl-3.0.10/ \\\nLDFLAGS="-L/usr/local/software/openssl-3.0.10/lib64" \\\nCPPFLAGS="-I/usr/local/software/openssl-3.0.10/include" \\\nPKG_CONFIG_PATH="/usr/local/software/openssl-3.0.10/lib64/pkgconfig"\n
\n

这样子一来,问题就迎刃而解了,编译安装完后,你会发现 Python 3.9.18 已经成功用用上了 OpenSSL 3.0.10 1 Aug 2023:

\n
$ python3 -c "import ssl; print(ssl.OPENSSL_VERSION)"\nOpenSSL 3.0.10 1 Aug 2023\n
\n

OpenSSL 3.0.10 on Python3.9.18

\n

参考资料

\n
    \n
  1. Drop support for OpenSSL<1.1.1 - urllib3/urllib3#2168
  2. \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '1.3.5-Python'}]}, 'comments': {'nodes': []}}, {'title': '富文本编辑器与 md 语法的一些困惑', 'number': 26, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/26', 'createdAt': '2023-12-01T02:29:00Z', 'lastEditedAt': '2023-12-01T05:34:04Z', 'updatedAt': '2023-12-01T05:34:04Z', 'body': '在语雀写文档写得多的,会对原始的 Markdown 越来越不敏感。\r\n\r\n语雀的富文本编辑器虽然支持的依然是 markdown,但也有它自身的一些与传统 markdown 不一样的写法,例如 [高亮块](https://www.yuque.com/yuque/gpvawt/rhhxkx)。这样的编辑器把 markdown 的源码给隐藏了——在用户编辑的时候实时进行渲染,这样对于不熟悉 markdown 的用户也极容易上手。\r\n\r\n\r\n\r\n但带来了一个问题,就是使用 markdown 对文档进行导出的时候,有时候会导致 markdown 格式错乱,尤其是当我们想要把语雀的一些文档导出到其他平台时候,这个问题特别烦人。\r\n\r\n![Markdown 语法异常](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/md-error.png)\r\n\r\n回到 GitHub,重新接触纯 Markdown 格式的写法,才真正感觉到这种模式的好处 —— 方便其他支持 Markdown 语法平台的转移,又可以最大限度解决 Markdown 语法错乱的尴尬。\r\n\r\n但也有不好的地方,就是对于多级有序缩进,插入代码后,有序序列(多级缩进)会被打断。。。。\r\n\r\n## 嵌套列表\r\n\r\n通过增加空格,Github 可以实现在嵌套列表中插入代码块;但是这样的做法在 MkDocs 中是有问题的。关于 MkDocs 的嵌套列表,在 https://github.com/mkdocs/mkdocs/issues/545 有一个讨论。\r\n\r\n参考的一个方法:,即使用 [superfences](https://facelessuser.github.io/pymdown-extensions/extensions/superfences/) 插件,加上基于 Python 特有的 4 的倍数个空格进行缩进,可以比较好解决这个问题。\r\n', 'bodyText': '在语雀写文档写得多的,会对原始的 Markdown 越来越不敏感。\n语雀的富文本编辑器虽然支持的依然是 markdown,但也有它自身的一些与传统 markdown 不一样的写法,例如 高亮块。这样的编辑器把 markdown 的源码给隐藏了——在用户编辑的时候实时进行渲染,这样对于不熟悉 markdown 的用户也极容易上手。\n\n但带来了一个问题,就是使用 markdown 对文档进行导出的时候,有时候会导致 markdown 格式错乱,尤其是当我们想要把语雀的一些文档导出到其他平台时候,这个问题特别烦人。\n\n回到 GitHub,重新接触纯 Markdown 格式的写法,才真正感觉到这种模式的好处 —— 方便其他支持 Markdown 语法平台的转移,又可以最大限度解决 Markdown 语法错乱的尴尬。\n但也有不好的地方,就是对于多级有序缩进,插入代码后,有序序列(多级缩进)会被打断。。。。\n嵌套列表\n通过增加空格,Github 可以实现在嵌套列表中插入代码块;但是这样的做法在 MkDocs 中是有问题的。关于 MkDocs 的嵌套列表,在 mkdocs/mkdocs#545 有一个讨论。\n参考的一个方法:mkdocs/mkdocs#2153,即使用 superfences 插件,加上基于 Python 特有的 4 的倍数个空格进行缩进,可以比较好解决这个问题。', 'bodyHTML': '

在语雀写文档写得多的,会对原始的 Markdown 越来越不敏感。

\n

语雀的富文本编辑器虽然支持的依然是 markdown,但也有它自身的一些与传统 markdown 不一样的写法,例如 高亮块。这样的编辑器把 markdown 的源码给隐藏了——在用户编辑的时候实时进行渲染,这样对于不熟悉 markdown 的用户也极容易上手。

\n\n

但带来了一个问题,就是使用 markdown 对文档进行导出的时候,有时候会导致 markdown 格式错乱,尤其是当我们想要把语雀的一些文档导出到其他平台时候,这个问题特别烦人。

\n

Markdown 语法异常

\n

回到 GitHub,重新接触纯 Markdown 格式的写法,才真正感觉到这种模式的好处 —— 方便其他支持 Markdown 语法平台的转移,又可以最大限度解决 Markdown 语法错乱的尴尬。

\n

但也有不好的地方,就是对于多级有序缩进,插入代码后,有序序列(多级缩进)会被打断。。。。

\n

嵌套列表

\n

通过增加空格,Github 可以实现在嵌套列表中插入代码块;但是这样的做法在 MkDocs 中是有问题的。关于 MkDocs 的嵌套列表,在 mkdocs/mkdocs#545 有一个讨论。

\n

参考的一个方法:mkdocs/mkdocs#2153,即使用 superfences 插件,加上基于 Python 特有的 4 的倍数个空格进行缩进,可以比较好解决这个问题。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '不同版本服务器间 SSH 免密码登录失败', 'number': 25, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/25', 'createdAt': '2023-11-30T05:43:06Z', 'lastEditedAt': '2023-12-01T03:01:45Z', 'updatedAt': '2024-01-03T07:56:12Z', 'body': "今天从服务器 A(CentOS 7.3)配置 SSH 无密码登录服务器 B(CentOS Steam 9),发现执行以下常规操作后无法实现:\r\n```\r\n$ ssh-keygen\r\n$ ssh-copy-id -i ~/.ssh/id_rsa.pub shenweiyan@66.xx.xx.xx # ssh-copy-id user@rhel-9-server-IP\r\n$ ssh shenweiyan@66.xx.xx.xx\r\n```\r\n![ssh-keygen-need-passwd](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/ssh-keygen-passwd.png)\r\n\r\n后来,更换 ecdsa 算法,问题才解决:\r\n```\r\n$ ssh-keygen -t ecdsa\r\n$ ssh-copy-id -i ~/.ssh/id_ecdsa.pub shenweiyan@66.xx.xx.xx\r\n```\r\n![ssh-keygen-ecdsa](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/ssh-keygen-ecdsa.png)\r\n\r\n根本原因就在于 SHA-1 已经在 RHEL9 中弃用了!\r\n\r\n从 RHEL9 的官网文档《[1.0.2. Crypto-policies, RHEL core cryptographic components, and protocols](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html-single/considerations_in_adopting_rhel_9/index#ref_considerations-security-crypto_changes-to-security)(加密策略、RHEL 核心加密组件和协议)》可以看到 SHA-1 已经在 RHEL9 中弃用了!\r\n> In RHEL 9, SHA-1 usage for signatures is restricted in the DEFAULT system-wide cryptographic policy. Except for HMAC, SHA-1 is no longer allowed in TLS, DTLS, SSH, IKEv2, DNSSEC, and Kerberos protocols. Individual applications not controlled by the RHEL system-wide crypto policies are also moving away from using SHA-1 hashes in RHEL 9.\r\n\r\n在 RHEL 9 中,用于签名的 SHA-1 用法在 DEFAULT 系统范围的加密策略中受到限制。除 HMAC 外,TLS、DTLS、**SSH**、IKEv2、DNSSEC 和 Kerberos 协议中不再允许使用 SHA-1。不受 RHEL 系统范围的加密策略控制的单个应用程序在 RHEL 9 中也不再使用 SHA-1 hashes。\r\n\r\n## 跨用户免密码登录\r\n\r\n从服务器 A(CentOS 7.3)的 root 用户已配置 SSH 无密码登录服务器 B(CentOS Steam 9)的 shenweiyan 用户。\r\n\r\n- 在服务器 A(CentOS 7.3)的 root 用户下执行以下命令,在 `/root/.ssh` 目录会得到两个文件:\r\n - 私钥文件:**id_ecdsa**\r\n - 公钥文件:**id_ecdsa.pub**\r\n```\r\nroot@centos-vm-7 11:47:20 ~ \r\n$ ssh-keygen -t ecdsa\r\nGenerating public/private ecdsa key pair.\r\nEnter file in which to save the key (/root/.ssh/id_ecdsa): \r\nEnter passphrase (empty for no passphrase): \r\nEnter same passphrase again: \r\nYour identification has been saved in /root/.ssh/id_ecdsa.\r\nYour public key has been saved in /root/.ssh/id_ecdsa.pub.\r\nThe key fingerprint is:\r\nad:15:01:5c:a9:db:69:64:2b:0c:4c:5f:be:f9:e1:44 root@centos-vm-7\r\nThe key's randomart image is:\r\n+--[ECDSA 256]---+\r\n| ..oo. |\r\n| . . o. |\r\n| o . +. |\r\n| o o.+.E |\r\n| oS=o* |\r\n| +oB o |\r\n| .o + . |\r\n| o |\r\n| |\r\n+-----------------+\r\n```\r\n\r\n- 把服务器 A 下 root 用户的公钥文件拷贝到服务器 B(CentOS Steam 9)的 shenweiyan 用户的 authorized_keys 中;\r\n```\r\nroot@centos-vm-7 11:53:25 ~\r\n$ ssh-copy-id -i ~/.ssh/id_ecdsa.pub shenweiyan@66.xx.xx.xx\r\n```\r\n\r\n- 将公钥拷贝至目标服务器 B 后,在源服务器 A 通过密钥跨用户免密码登录云服务器。\r\n```\r\nroot@centos-vm-7 11:58:47 /root \r\n$ ssh shenweiyan@66.xx.xx.xx # ssh -i id_ecdsa shenweiyan@66.xx.xx.xx\r\n```\r\n\r\n## 参考资料\r\n- [RHEL6 ssh 到 RHEL9 的 no hostkey alg 错误](https://www.yuque.com/shenweiyan/cookbook/rhel-9-no-hostkey-alg),语雀\r\n- [How can I use a legacy ssh-rsa key on CentOS 9 Stream?](https://serverfault.com/questions/1095898/how-can-i-use-a-legacy-ssh-rsa-key-on-centos-9-stream),Server Fault\r\n", 'bodyText': "今天从服务器 A(CentOS 7.3)配置 SSH 无密码登录服务器 B(CentOS Steam 9),发现执行以下常规操作后无法实现:\n$ ssh-keygen\n$ ssh-copy-id -i ~/.ssh/id_rsa.pub shenweiyan@66.xx.xx.xx # ssh-copy-id user@rhel-9-server-IP\n$ ssh shenweiyan@66.xx.xx.xx\n\n\n后来,更换 ecdsa 算法,问题才解决:\n$ ssh-keygen -t ecdsa\n$ ssh-copy-id -i ~/.ssh/id_ecdsa.pub shenweiyan@66.xx.xx.xx\n\n\n根本原因就在于 SHA-1 已经在 RHEL9 中弃用了!\n从 RHEL9 的官网文档《1.0.2. Crypto-policies, RHEL core cryptographic components, and protocols(加密策略、RHEL 核心加密组件和协议)》可以看到 SHA-1 已经在 RHEL9 中弃用了!\n\nIn RHEL 9, SHA-1 usage for signatures is restricted in the DEFAULT system-wide cryptographic policy. Except for HMAC, SHA-1 is no longer allowed in TLS, DTLS, SSH, IKEv2, DNSSEC, and Kerberos protocols. Individual applications not controlled by the RHEL system-wide crypto policies are also moving away from using SHA-1 hashes in RHEL 9.\n\n在 RHEL 9 中,用于签名的 SHA-1 用法在 DEFAULT 系统范围的加密策略中受到限制。除 HMAC 外,TLS、DTLS、SSH、IKEv2、DNSSEC 和 Kerberos 协议中不再允许使用 SHA-1。不受 RHEL 系统范围的加密策略控制的单个应用程序在 RHEL 9 中也不再使用 SHA-1 hashes。\n跨用户免密码登录\n从服务器 A(CentOS 7.3)的 root 用户已配置 SSH 无密码登录服务器 B(CentOS Steam 9)的 shenweiyan 用户。\n\n在服务器 A(CentOS 7.3)的 root 用户下执行以下命令,在 /root/.ssh 目录会得到两个文件:\n\n私钥文件:id_ecdsa\n公钥文件:id_ecdsa.pub\n\n\n\nroot@centos-vm-7 11:47:20 ~ \n$ ssh-keygen -t ecdsa\nGenerating public/private ecdsa key pair.\nEnter file in which to save the key (/root/.ssh/id_ecdsa): \nEnter passphrase (empty for no passphrase): \nEnter same passphrase again: \nYour identification has been saved in /root/.ssh/id_ecdsa.\nYour public key has been saved in /root/.ssh/id_ecdsa.pub.\nThe key fingerprint is:\nad:15:01:5c:a9:db:69:64:2b:0c:4c:5f:be:f9:e1:44 root@centos-vm-7\nThe key's randomart image is:\n+--[ECDSA 256]---+\n| ..oo. |\n| . . o. |\n| o . +. |\n| o o.+.E |\n| oS=o* |\n| +oB o |\n| .o + . |\n| o |\n| |\n+-----------------+\n\n\n把服务器 A 下 root 用户的公钥文件拷贝到服务器 B(CentOS Steam 9)的 shenweiyan 用户的 authorized_keys 中;\n\nroot@centos-vm-7 11:53:25 ~\n$ ssh-copy-id -i ~/.ssh/id_ecdsa.pub shenweiyan@66.xx.xx.xx\n\n\n将公钥拷贝至目标服务器 B 后,在源服务器 A 通过密钥跨用户免密码登录云服务器。\n\nroot@centos-vm-7 11:58:47 /root \n$ ssh shenweiyan@66.xx.xx.xx # ssh -i id_ecdsa shenweiyan@66.xx.xx.xx\n\n参考资料\n\nRHEL6 ssh 到 RHEL9 的 no hostkey alg 错误,语雀\nHow can I use a legacy ssh-rsa key on CentOS 9 Stream?,Server Fault", 'bodyHTML': '

今天从服务器 A(CentOS 7.3)配置 SSH 无密码登录服务器 B(CentOS Steam 9),发现执行以下常规操作后无法实现:

\n
$ ssh-keygen\n$ ssh-copy-id -i ~/.ssh/id_rsa.pub shenweiyan@66.xx.xx.xx  # ssh-copy-id user@rhel-9-server-IP\n$ ssh shenweiyan@66.xx.xx.xx\n
\n

ssh-keygen-need-passwd

\n

后来,更换 ecdsa 算法,问题才解决:

\n
$ ssh-keygen -t ecdsa\n$ ssh-copy-id -i ~/.ssh/id_ecdsa.pub shenweiyan@66.xx.xx.xx\n
\n

ssh-keygen-ecdsa

\n

根本原因就在于 SHA-1 已经在 RHEL9 中弃用了!

\n

从 RHEL9 的官网文档《1.0.2. Crypto-policies, RHEL core cryptographic components, and protocols(加密策略、RHEL 核心加密组件和协议)》可以看到 SHA-1 已经在 RHEL9 中弃用了!

\n
\n

In RHEL 9, SHA-1 usage for signatures is restricted in the DEFAULT system-wide cryptographic policy. Except for HMAC, SHA-1 is no longer allowed in TLS, DTLS, SSH, IKEv2, DNSSEC, and Kerberos protocols. Individual applications not controlled by the RHEL system-wide crypto policies are also moving away from using SHA-1 hashes in RHEL 9.

\n
\n

在 RHEL 9 中,用于签名的 SHA-1 用法在 DEFAULT 系统范围的加密策略中受到限制。除 HMAC 外,TLS、DTLS、SSH、IKEv2、DNSSEC 和 Kerberos 协议中不再允许使用 SHA-1。不受 RHEL 系统范围的加密策略控制的单个应用程序在 RHEL 9 中也不再使用 SHA-1 hashes。

\n

跨用户免密码登录

\n

从服务器 A(CentOS 7.3)的 root 用户已配置 SSH 无密码登录服务器 B(CentOS Steam 9)的 shenweiyan 用户。

\n
    \n
  • 在服务器 A(CentOS 7.3)的 root 用户下执行以下命令,在 /root/.ssh 目录会得到两个文件:\n
      \n
    • 私钥文件:id_ecdsa
    • \n
    • 公钥文件:id_ecdsa.pub
    • \n
    \n
  • \n
\n
root@centos-vm-7 11:47:20 ~ \n$ ssh-keygen -t ecdsa\nGenerating public/private ecdsa key pair.\nEnter file in which to save the key (/root/.ssh/id_ecdsa): \nEnter passphrase (empty for no passphrase): \nEnter same passphrase again: \nYour identification has been saved in /root/.ssh/id_ecdsa.\nYour public key has been saved in /root/.ssh/id_ecdsa.pub.\nThe key fingerprint is:\nad:15:01:5c:a9:db:69:64:2b:0c:4c:5f:be:f9:e1:44 root@centos-vm-7\nThe key\'s randomart image is:\n+--[ECDSA  256]---+\n|       ..oo.     |\n|      . . o.     |\n|     o . +.      |\n|      o o.+.E    |\n|       oS=o*     |\n|        +oB o    |\n|        .o + .   |\n|            o    |\n|                 |\n+-----------------+\n
\n
    \n
  • 把服务器 A 下 root 用户的公钥文件拷贝到服务器 B(CentOS Steam 9)的 shenweiyan 用户的 authorized_keys 中;
  • \n
\n
root@centos-vm-7 11:53:25 ~\n$ ssh-copy-id -i ~/.ssh/id_ecdsa.pub shenweiyan@66.xx.xx.xx\n
\n
    \n
  • 将公钥拷贝至目标服务器 B 后,在源服务器 A 通过密钥跨用户免密码登录云服务器。
  • \n
\n
root@centos-vm-7 11:58:47 /root \n$ ssh shenweiyan@66.xx.xx.xx  # ssh -i id_ecdsa shenweiyan@66.xx.xx.xx\n
\n

参考资料

\n', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '1.3.17-服务器配置使用'}]}, 'comments': {'nodes': []}}, {'title': 'Micro/Mamba 安装与注意事项', 'number': 24, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/24', 'createdAt': '2023-11-27T05:37:10Z', 'lastEditedAt': '2024-03-19T06:59:48Z', 'updatedAt': '2024-03-19T06:59:48Z', 'body': '记录一下 Micromamba/Mamba 安装的步骤和注意事项。\r\n\r\n## Mamba 安装\r\n\r\nMamba 可以使用 Mambaforge 方法和已有 Mini/conda 的方式安装,官方推荐的是前面一种,即使用 Mambaforge 进行全新安装。\r\n\r\n### 全新安装\r\n关于 mamba 的安装,官方推荐 [Fresh install](https://mamba.readthedocs.io/en/latest/mamba-installation.html),即全新安装。\r\n\r\n> We recommend that you start with the [Mambaforge distribution](https://github.com/conda-forge/miniforge#mambaforge). Mambaforge comes with the popular conda-forge channel preconfigured, but you can modify the configuration to use any channel you like. Note that Anaconda channels are generally incompatible with conda-forge, so you should not mix them. \r\n> 我们建议您从 Mambaforge 发行版开始。 Mambaforge 预配置了流行的 conda-forge 通道,但您可以修改配置以使用您喜欢的任何通道。请注意,Anaconda 通道通常与 conda-forge 不兼容,因此您不应混合使用它们。\r\n\r\n其实就是: \r\n1. 先去 [Mambaforge distribution](https://github.com/conda-forge/miniforge#mambaforge) 下载 Mambaforge-Linux-x86_64.sh。 \r\n2. 执行 `sh Mambaforge-Linux-x86_64.sh` 安装命令。\r\n\r\n### 在已有的 conda 中安装\r\n\r\n官方文档中明确说不推荐这种安装 Mamba 的方式,他们强烈建议使用 Mambaforge 方法(见上文)。\r\n\r\n这种方法,要获取 `mamba` ,其实只需将其从 `conda-forge` 通道安装到基础环境中即可;但是需要注意 **Installing mamba into any other environment than base is not supported**,即**不支持将 mamba 安装到 base 之外的任何其他环境中**。\r\n\r\n首先,安装 Miniconda。\r\n\r\n参考 ,下载完 Miniconda3-latest-Linux-x86_64.sh,sh 执行一下就可以安装了。\r\n```\r\nsh Miniconda3-latest-Linux-x86_64.sh\r\n```\r\n然后,安装 mamba。\r\n```\r\n~/miniconda3/bin/conda install -c conda-forge mamba\r\n```\r\n\r\n> For both `mamba` and `conda`, the `base` environment is meant to hold their dependencies. It is strongly discouraged to install anything else in the base envionment. Doing so may break `mamba` and `conda` installation. \r\n> 对于 `mamba` 和 `conda` , `base` 环境旨在保存它们的依赖关系。强烈建议不要在基础环境中安装任何其他东西。这样做可能会破坏 `mamba` 和 `conda` 安装。\r\n\r\n## Micromamba 安装\r\n参考 。\r\n\r\n> `micromamba` is a fully statically-linked, self-contained, executable. This means that the `base` environment is completely empty. The configuration for `micromamba` is slighly different, namely all environments and cache will be created by default under the `MAMBA_ROOT_PREFIX` environment variable. There is also no pre-configured `.condarc`/`.mambarc` shipped with micromamba (they are however still read if present). \r\n> `micromamba` 是一个完全静态链接的、独立的可执行文件。这意味着 `base` 环境完全是空的。`micromamba` 的配置略有不同,即默认情况下将在 `MAMBA_ROOT_PREFIX` 环境变量下创建所有环境和缓存。`micromamba` 也没有预配置的 `.condarc` / `.mambarc`(但是,如果存在,它们仍然会被读取)。\r\n\r\n### 脚本安装\r\n\r\n如果您使用的是 macOS、Linux 或 Windows 上的 Git Bash,则有一种简单的安装方法 `micromamba`。只需在您喜欢的 shell 中执行安装脚本即可。\r\n\r\n对于 Linux、macOS 或 Windows 上的 Git Bash,请使用以下命令安装:\r\n```\r\n"${SHELL}" <(curl -L micro.mamba.pm/install.sh)\r\n```\r\n\r\n### 自动更新\r\n安装后,`micromamba` 可以通过下面的方式更新:\r\n```\r\nmicromamba self-update\r\n```\r\n可以指定显式版本:\r\n```\r\nmicromamba self-update --version 1.4.6\r\n```\r\n### 手动更新\r\n\r\n#### Linux 和 macOS\r\n下载并解压可执行文件(来自官方 `conda-forge` 包)即可。\r\n> 其实,这就等同于我们直接去 下载对应平台的二进制文件,或者 `tar.bz2` 文件,然后解压缩,把 `bin/micromamba` 部分提出来使用。\r\n\r\n确保安装了基本实用程序。我们需要 `curl` 和 `tar` 并支持 `bzip2` 。此外,您还需要一个基于 glibc 的系统,例如 Ubuntu、Fedora 或 Centos(Alpine Linux 本身无法运行)。\r\n\r\n以下 magic URL 始终返回 micromamba 的最新可用版本,并且使用 `tar` 自动提取 `bin/micromamba` 部分。\r\n```\r\n# Linux Intel (x86_64):\r\ncurl -Ls https://micro.mamba.pm/api/micromamba/linux-64/latest | tar -xvj bin/micromamba\r\n# Linux ARM64:\r\ncurl -Ls https://micro.mamba.pm/api/micromamba/linux-aarch64/latest | tar -xvj bin/micromamba\r\n# Linux Power:\r\ncurl -Ls https://micro.mamba.pm/api/micromamba/linux-ppc64le/latest | tar -xvj bin/micromamba\r\n# macOS Intel (x86_64):\r\ncurl -Ls https://micro.mamba.pm/api/micromamba/osx-64/latest | tar -xvj bin/micromamba\r\n# macOS Silicon/M1 (ARM64):\r\ncurl -Ls https://micro.mamba.pm/api/micromamba/osx-arm64/latest | tar -xvj bin/micromamba\r\n```\r\n提取完成后,我们就可以使用 `micromamba` 二进制文件了。\r\n\r\n如果您想在临时用例中快速使用 micromamba,您可以运行:\r\n```\r\nexport MAMBA_ROOT_PREFIX=/some/prefix # optional, defaults to ~/micromamba\r\neval "$(./bin/micromamba shell hook -s posix)"\r\n```\r\n这个 shell hook 会修改您的 shell 变量以包含 micromamba 命令。\r\n\r\n如果您想保留这些更改,可以通过运行 `./micromamba shell init ...` 自动将它们写入 `.bashrc` (或 `.zshrc` )。这还允许您选择自定义 MAMBA_ROOT_ENVIRONMENT,这是包和 repodata 缓存所在的位置。\r\n```\r\n# Linux/bash:\r\n./bin/micromamba shell init -s bash -p ~/micromamba # this writes to your .bashrc file\r\n# sourcing the bashrc file incorporates the changes into the running session.\r\n# better yet, restart your terminal!\r\nsource ~/.bashrc\r\n\r\n# macOS/zsh:\r\n./micromamba shell init -s zsh -p ~/micromamba\r\nsource ~/.zshrc\r\n```\r\n\r\n现在您可以激活基本环境并安装新软件包,或创建其他环境。\r\n```\r\nmicromamba activate # this activates the base environment\r\nmicromamba install python=3.6 jupyter -c conda-forge\r\n# or\r\nmicromamba create -n env_name xtensor -c conda-forge\r\nmicromamba activate env_name\r\n```\r\n\r\n专有的 [conda-forge](https://conda-forge.org/) 设置可以配置为:\r\n```\r\nmicromamba config append channels conda-forge\r\nmicromamba config append channels nodefaults\r\nmicromamba config set channel_priority strict\r\n```\r\n', 'bodyText': '记录一下 Micromamba/Mamba 安装的步骤和注意事项。\nMamba 安装\nMamba 可以使用 Mambaforge 方法和已有 Mini/conda 的方式安装,官方推荐的是前面一种,即使用 Mambaforge 进行全新安装。\n全新安装\n关于 mamba 的安装,官方推荐 Fresh install,即全新安装。\n\nWe recommend that you start with the Mambaforge distribution. Mambaforge comes with the popular conda-forge channel preconfigured, but you can modify the configuration to use any channel you like. Note that Anaconda channels are generally incompatible with conda-forge, so you should not mix them.\n我们建议您从 Mambaforge 发行版开始。 Mambaforge 预配置了流行的 conda-forge 通道,但您可以修改配置以使用您喜欢的任何通道。请注意,Anaconda 通道通常与 conda-forge 不兼容,因此您不应混合使用它们。\n\n其实就是:\n\n先去 Mambaforge distribution 下载 Mambaforge-Linux-x86_64.sh。\n执行 sh Mambaforge-Linux-x86_64.sh 安装命令。\n\n在已有的 conda 中安装\n官方文档中明确说不推荐这种安装 Mamba 的方式,他们强烈建议使用 Mambaforge 方法(见上文)。\n这种方法,要获取 mamba ,其实只需将其从 conda-forge 通道安装到基础环境中即可;但是需要注意 Installing mamba into any other environment than base is not supported,即不支持将 mamba 安装到 base 之外的任何其他环境中。\n首先,安装 Miniconda。\n参考 https://docs.conda.io/en/latest/miniconda.html,下载完 Miniconda3-latest-Linux-x86_64.sh,sh 执行一下就可以安装了。\nsh Miniconda3-latest-Linux-x86_64.sh\n\n然后,安装 mamba。\n~/miniconda3/bin/conda install -c conda-forge mamba\n\n\nFor both mamba and conda, the base environment is meant to hold their dependencies. It is strongly discouraged to install anything else in the base envionment. Doing so may break mamba and conda installation.\n对于 mamba 和 conda , base 环境旨在保存它们的依赖关系。强烈建议不要在基础环境中安装任何其他东西。这样做可能会破坏 mamba 和 conda 安装。\n\nMicromamba 安装\n参考 https://mamba.readthedocs.io/en/latest/micromamba-installation.html。\n\nmicromamba is a fully statically-linked, self-contained, executable. This means that the base environment is completely empty. The configuration for micromamba is slighly different, namely all environments and cache will be created by default under the MAMBA_ROOT_PREFIX environment variable. There is also no pre-configured .condarc/.mambarc shipped with micromamba (they are however still read if present).\nmicromamba 是一个完全静态链接的、独立的可执行文件。这意味着 base 环境完全是空的。micromamba 的配置略有不同,即默认情况下将在 MAMBA_ROOT_PREFIX 环境变量下创建所有环境和缓存。micromamba 也没有预配置的 .condarc / .mambarc(但是,如果存在,它们仍然会被读取)。\n\n脚本安装\n如果您使用的是 macOS、Linux 或 Windows 上的 Git Bash,则有一种简单的安装方法 micromamba。只需在您喜欢的 shell 中执行安装脚本即可。\n对于 Linux、macOS 或 Windows 上的 Git Bash,请使用以下命令安装:\n"${SHELL}" <(curl -L micro.mamba.pm/install.sh)\n\n自动更新\n安装后,micromamba 可以通过下面的方式更新:\nmicromamba self-update\n\n可以指定显式版本:\nmicromamba self-update --version 1.4.6\n\n手动更新\nLinux 和 macOS\n下载并解压可执行文件(来自官方 conda-forge 包)即可。\n\n其实,这就等同于我们直接去 https://github.com/mamba-org/micromamba-releases/releases 下载对应平台的二进制文件,或者 tar.bz2 文件,然后解压缩,把 bin/micromamba 部分提出来使用。\n\n确保安装了基本实用程序。我们需要 curl 和 tar 并支持 bzip2 。此外,您还需要一个基于 glibc 的系统,例如 Ubuntu、Fedora 或 Centos(Alpine Linux 本身无法运行)。\n以下 magic URL 始终返回 micromamba 的最新可用版本,并且使用 tar 自动提取 bin/micromamba 部分。\n# Linux Intel (x86_64):\ncurl -Ls https://micro.mamba.pm/api/micromamba/linux-64/latest | tar -xvj bin/micromamba\n# Linux ARM64:\ncurl -Ls https://micro.mamba.pm/api/micromamba/linux-aarch64/latest | tar -xvj bin/micromamba\n# Linux Power:\ncurl -Ls https://micro.mamba.pm/api/micromamba/linux-ppc64le/latest | tar -xvj bin/micromamba\n# macOS Intel (x86_64):\ncurl -Ls https://micro.mamba.pm/api/micromamba/osx-64/latest | tar -xvj bin/micromamba\n# macOS Silicon/M1 (ARM64):\ncurl -Ls https://micro.mamba.pm/api/micromamba/osx-arm64/latest | tar -xvj bin/micromamba\n\n提取完成后,我们就可以使用 micromamba 二进制文件了。\n如果您想在临时用例中快速使用 micromamba,您可以运行:\nexport MAMBA_ROOT_PREFIX=/some/prefix # optional, defaults to ~/micromamba\neval "$(./bin/micromamba shell hook -s posix)"\n\n这个 shell hook 会修改您的 shell 变量以包含 micromamba 命令。\n如果您想保留这些更改,可以通过运行 ./micromamba shell init ... 自动将它们写入 .bashrc (或 .zshrc )。这还允许您选择自定义 MAMBA_ROOT_ENVIRONMENT,这是包和 repodata 缓存所在的位置。\n# Linux/bash:\n./bin/micromamba shell init -s bash -p ~/micromamba # this writes to your .bashrc file\n# sourcing the bashrc file incorporates the changes into the running session.\n# better yet, restart your terminal!\nsource ~/.bashrc\n\n# macOS/zsh:\n./micromamba shell init -s zsh -p ~/micromamba\nsource ~/.zshrc\n\n现在您可以激活基本环境并安装新软件包,或创建其他环境。\nmicromamba activate # this activates the base environment\nmicromamba install python=3.6 jupyter -c conda-forge\n# or\nmicromamba create -n env_name xtensor -c conda-forge\nmicromamba activate env_name\n\n专有的 conda-forge 设置可以配置为:\nmicromamba config append channels conda-forge\nmicromamba config append channels nodefaults\nmicromamba config set channel_priority strict', 'bodyHTML': '

记录一下 Micromamba/Mamba 安装的步骤和注意事项。

\n

Mamba 安装

\n

Mamba 可以使用 Mambaforge 方法和已有 Mini/conda 的方式安装,官方推荐的是前面一种,即使用 Mambaforge 进行全新安装。

\n

全新安装

\n

关于 mamba 的安装,官方推荐 Fresh install,即全新安装。

\n
\n

We recommend that you start with the Mambaforge distribution. Mambaforge comes with the popular conda-forge channel preconfigured, but you can modify the configuration to use any channel you like. Note that Anaconda channels are generally incompatible with conda-forge, so you should not mix them.
\n我们建议您从 Mambaforge 发行版开始。 Mambaforge 预配置了流行的 conda-forge 通道,但您可以修改配置以使用您喜欢的任何通道。请注意,Anaconda 通道通常与 conda-forge 不兼容,因此您不应混合使用它们。

\n
\n

其实就是:

\n
    \n
  1. 先去 Mambaforge distribution 下载 Mambaforge-Linux-x86_64.sh。
  2. \n
  3. 执行 sh Mambaforge-Linux-x86_64.sh 安装命令。
  4. \n
\n

在已有的 conda 中安装

\n

官方文档中明确说不推荐这种安装 Mamba 的方式,他们强烈建议使用 Mambaforge 方法(见上文)。

\n

这种方法,要获取 mamba ,其实只需将其从 conda-forge 通道安装到基础环境中即可;但是需要注意 Installing mamba into any other environment than base is not supported,即不支持将 mamba 安装到 base 之外的任何其他环境中

\n

首先,安装 Miniconda。

\n

参考 https://docs.conda.io/en/latest/miniconda.html,下载完 Miniconda3-latest-Linux-x86_64.sh,sh 执行一下就可以安装了。

\n
sh Miniconda3-latest-Linux-x86_64.sh\n
\n

然后,安装 mamba。

\n
~/miniconda3/bin/conda install -c conda-forge mamba\n
\n
\n

For both mamba and conda, the base environment is meant to hold their dependencies. It is strongly discouraged to install anything else in the base envionment. Doing so may break mamba and conda installation.
\n对于 mambacondabase 环境旨在保存它们的依赖关系。强烈建议不要在基础环境中安装任何其他东西。这样做可能会破坏 mambaconda 安装。

\n
\n

Micromamba 安装

\n

参考 https://mamba.readthedocs.io/en/latest/micromamba-installation.html

\n
\n

micromamba is a fully statically-linked, self-contained, executable. This means that the base environment is completely empty. The configuration for micromamba is slighly different, namely all environments and cache will be created by default under the MAMBA_ROOT_PREFIX environment variable. There is also no pre-configured .condarc/.mambarc shipped with micromamba (they are however still read if present).
\nmicromamba 是一个完全静态链接的、独立的可执行文件。这意味着 base 环境完全是空的。micromamba 的配置略有不同,即默认情况下将在 MAMBA_ROOT_PREFIX 环境变量下创建所有环境和缓存。micromamba 也没有预配置的 .condarc / .mambarc(但是,如果存在,它们仍然会被读取)。

\n
\n

脚本安装

\n

如果您使用的是 macOS、Linux 或 Windows 上的 Git Bash,则有一种简单的安装方法 micromamba。只需在您喜欢的 shell 中执行安装脚本即可。

\n

对于 Linux、macOS 或 Windows 上的 Git Bash,请使用以下命令安装:

\n
"${SHELL}" <(curl -L micro.mamba.pm/install.sh)\n
\n

自动更新

\n

安装后,micromamba 可以通过下面的方式更新:

\n
micromamba self-update\n
\n

可以指定显式版本:

\n
micromamba self-update --version 1.4.6\n
\n

手动更新

\n

Linux 和 macOS

\n

下载并解压可执行文件(来自官方 conda-forge 包)即可。

\n
\n

其实,这就等同于我们直接去 https://github.com/mamba-org/micromamba-releases/releases 下载对应平台的二进制文件,或者 tar.bz2 文件,然后解压缩,把 bin/micromamba 部分提出来使用。

\n
\n

确保安装了基本实用程序。我们需要 curltar 并支持 bzip2 。此外,您还需要一个基于 glibc 的系统,例如 Ubuntu、Fedora 或 Centos(Alpine Linux 本身无法运行)。

\n

以下 magic URL 始终返回 micromamba 的最新可用版本,并且使用 tar 自动提取 bin/micromamba 部分。

\n
# Linux Intel (x86_64):\ncurl -Ls https://micro.mamba.pm/api/micromamba/linux-64/latest | tar -xvj bin/micromamba\n# Linux ARM64:\ncurl -Ls https://micro.mamba.pm/api/micromamba/linux-aarch64/latest | tar -xvj bin/micromamba\n# Linux Power:\ncurl -Ls https://micro.mamba.pm/api/micromamba/linux-ppc64le/latest | tar -xvj bin/micromamba\n# macOS Intel (x86_64):\ncurl -Ls https://micro.mamba.pm/api/micromamba/osx-64/latest | tar -xvj bin/micromamba\n# macOS Silicon/M1 (ARM64):\ncurl -Ls https://micro.mamba.pm/api/micromamba/osx-arm64/latest | tar -xvj bin/micromamba\n
\n

提取完成后,我们就可以使用 micromamba 二进制文件了。

\n

如果您想在临时用例中快速使用 micromamba,您可以运行:

\n
export MAMBA_ROOT_PREFIX=/some/prefix  # optional, defaults to ~/micromamba\neval "$(./bin/micromamba shell hook -s posix)"\n
\n

这个 shell hook 会修改您的 shell 变量以包含 micromamba 命令。

\n

如果您想保留这些更改,可以通过运行 ./micromamba shell init ... 自动将它们写入 .bashrc (或 .zshrc )。这还允许您选择自定义 MAMBA_ROOT_ENVIRONMENT,这是包和 repodata 缓存所在的位置。

\n
# Linux/bash:\n./bin/micromamba shell init -s bash -p ~/micromamba  # this writes to your .bashrc file\n# sourcing the bashrc file incorporates the changes into the running session.\n# better yet, restart your terminal!\nsource ~/.bashrc\n\n# macOS/zsh:\n./micromamba shell init -s zsh -p ~/micromamba\nsource ~/.zshrc\n
\n

现在您可以激活基本环境并安装新软件包,或创建其他环境。

\n
micromamba activate  # this activates the base environment\nmicromamba install python=3.6 jupyter -c conda-forge\n# or\nmicromamba create -n env_name xtensor -c conda-forge\nmicromamba activate env_name\n
\n

专有的 conda-forge 设置可以配置为:

\n
micromamba config append channels conda-forge\nmicromamba config append channels nodefaults\nmicromamba config set channel_priority strict\n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '1.3.22-虚拟环境'}]}, 'comments': {'nodes': []}}, {'title': '大学计算机没有的一课', 'number': 23, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/23', 'createdAt': '2023-11-23T02:04:09Z', 'lastEditedAt': None, 'updatedAt': '2023-11-23T02:04:10Z', 'body': '今天是2023年1月19日,马上要过年了,在这里先提前给大家拜年了,祝大家新年快乐,阖家幸福安康!\r\n\r\n今天来给大家推荐一个不错的开源项目。\r\n\r\n\r\n\r\n大学里的计算机课程往往只专注于讲授数据结构、操作系统这些知识,对于编程开发中常用的工具则留给学生自行学习。在 MIT 这个课程中,你可以了解和掌握命令行(shell)、文本编辑器(Vim)、版本控制系统(Git)等强大的工具,越早接触越能更加熟练地使用它们,有助于未来的职业生涯。\r\n![missing-semester](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/23019-missing-semester.png)\r\n\r\n**地址:**\r\n**中文:**\r\n', 'bodyText': '今天是2023年1月19日,马上要过年了,在这里先提前给大家拜年了,祝大家新年快乐,阖家幸福安康!\n今天来给大家推荐一个不错的开源项目。\n\n大学里的计算机课程往往只专注于讲授数据结构、操作系统这些知识,对于编程开发中常用的工具则留给学生自行学习。在 MIT 这个课程中,你可以了解和掌握命令行(shell)、文本编辑器(Vim)、版本控制系统(Git)等强大的工具,越早接触越能更加熟练地使用它们,有助于未来的职业生涯。\n\n地址:https://github.com/missing-semester/missing-semester\n中文:https://missing-semester-cn.github.io/', 'bodyHTML': '

今天是2023年1月19日,马上要过年了,在这里先提前给大家拜年了,祝大家新年快乐,阖家幸福安康!

\n

今天来给大家推荐一个不错的开源项目。

\n\n

大学里的计算机课程往往只专注于讲授数据结构、操作系统这些知识,对于编程开发中常用的工具则留给学生自行学习。在 MIT 这个课程中,你可以了解和掌握命令行(shell)、文本编辑器(Vim)、版本控制系统(Git)等强大的工具,越早接触越能更加熟练地使用它们,有助于未来的职业生涯。
\nmissing-semester

\n

地址:https://github.com/missing-semester/missing-semester
\n中文:https://missing-semester-cn.github.io/

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.4-知识'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'Notepad++ 在 GitHub 已经沦为战场了', 'number': 22, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/22', 'createdAt': '2023-11-23T01:59:33Z', 'lastEditedAt': '2024-07-16T05:38:26Z', 'updatedAt': '2024-07-16T05:38:26Z', 'body': 'Notepad++ 这片瓜田的瓜都吃了好几年了,作者却一直还在死性不改 。。。。。\r\n\r\n同样的 Notepad++ 在 GitHub 仓库 [notepad-plus-plus](https://github.com/notepad-plus-plus/notepad-plus-plus) 早已沦为反华辱华的垃圾场,群魔乱舞,简直惨不忍睹!\r\n\r\n\r\n\r\n\'say-no-to-Notepad++\'\r\n\r\n## Add random characters\r\n\r\nTwitter: \r\nV2EX:\r\n\r\n![Twitter Notepad++](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/twitter-notepad%2B%2B.png)\r\n\r\n## Free Uyghur\r\n\r\n不知道大家有没有留意,前两天(2019 年 10 月 29)开源文本编辑器 Notepad++ 发布了最新的 \xa0[7.8.1](https://notepad-plus-plus.org/downloads/v7.8.1/)\xa0 版本。\r\n\r\n然而,软件新版本发布后,在该版本中 Notepad++ 的作者同时附加了一篇名为《[Notepad++ v7.8.1 : Free Uyghur](https://notepad-plus-plus.org/news/v781-free-uyghur-edition/)》抹黑中国的文章,具体的内容请大家自行百度(图片是文章部分截图)。而且这已经不是 Notepad++ 第一次这么干了!\r\n![Notepad++ Free Uyghur](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/notepad%2B%2Bv781.png)\r\n\r\nNotepad++ 的 "Free Uyghur" 出来以后,Notepad++ 所在的 Github 瞬间被广大中国的开发者占领,他们用自己的方式进行了回击。小编也忍不住上去看一下,发现 \xa0GitHub 上面基本上都是骂 Notepad++ 作者的,不过也有少数支持作者。\r\n![notepad-781-github-issue1](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/notepad-781-github-issue1.png)\r\n\r\n![notepad-781-github-issue2](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/notepad-781-github-issue2.png)\r\n\r\n## 起底一下开发者\r\n\r\n后来查了一下,Notepad++ 的作者,原来名字叫做侯今吾(英语:DonHO,),是一个毕业于台湾淡江大学及巴黎第七大学的电脑工程师,作为一个台湾人,也是一个台独积极分子,侯今吾借助 Notepad++ 抹黑中国可谓由来已久。\r\n\r\n![Notepad++ DonHO](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/notepad-donho.png)\r\n\r\n## 我也来说几句\r\n\r\n在这里我想说的是,Notepad++ 作为一款免费开源,深受国外编程爱好者赞扬,也为台湾开源界赢得好评,效率很高的文本编辑器,在早年间也是小编最喜欢常用的软件之一。但对于政见这件事情,小编觉得就像吃一道菜一样,你可以选择吃与不吃,不吃,你可以一笑而过,喜欢的人照常吃,与你无关,但你绝对不能吐一口脏东西上去。\r\n\r\n软件本身是没什么问题的,要说软件和作者之间的关系,那就是爱用不用的关系了。同类软件,我不喜欢你作者,当然就不用了,当然我不用也不会对软件发展有什么影响,不过我想说,这就像是去餐馆吃饭。对于顾客来说,他吃与不吃,不会影响服务员的工资。但对于服务员来说,至少不能让顾客觉得你讨厌。\r\n\r\n最后,有人说要抵制 Notepad++,但对我而言,小编是反对把开源与政治挂钩的,因此小编选择不用 Notepad++ —— 我有选择的权利,既然开源的编辑器那么多(我可以用 [Sublime Text](https://www.sublimetext.com/) (虽然 [Sublime Text](https://www.sublimetext.com/) 是非开源的),可以用 [Visual Studio Code](https://code.visualstudio.com/),可以用 [Github Atom](https://atom.io/),也可以用 [BowPad](https://tools.stefankueng.com/BowPad.html)、[Editra](http://editra.org/),甚至是国人开发的 [Notepad--](https://gitee.com/cxasm/notepad--)),我又何必选择一个带政治倾向自己又不喜欢的编辑器呢!\r\n', 'bodyText': 'Notepad++ 这片瓜田的瓜都吃了好几年了,作者却一直还在死性不改 。。。。。\n同样的 Notepad++ 在 GitHub 仓库 notepad-plus-plus 早已沦为反华辱华的垃圾场,群魔乱舞,简直惨不忍睹!\n\n\nAdd random characters\nTwitter:https://twitter.com/Notepad_plus/status/1618276938342359042\nV2EX:https://www.v2ex.com/t/910777\n\nFree Uyghur\n不知道大家有没有留意,前两天(2019 年 10 月 29)开源文本编辑器 Notepad++ 发布了最新的 \xa07.8.1\xa0 版本。\n然而,软件新版本发布后,在该版本中 Notepad++ 的作者同时附加了一篇名为《Notepad++ v7.8.1 : Free Uyghur》抹黑中国的文章,具体的内容请大家自行百度(图片是文章部分截图)。而且这已经不是 Notepad++ 第一次这么干了!\n\nNotepad++ 的 "Free Uyghur" 出来以后,Notepad++ 所在的 Github 瞬间被广大中国的开发者占领,他们用自己的方式进行了回击。小编也忍不住上去看一下,发现 \xa0GitHub 上面基本上都是骂 Notepad++ 作者的,不过也有少数支持作者。\n\n\n起底一下开发者\n后来查了一下,Notepad++ 的作者,原来名字叫做侯今吾(英语:DonHO,https://github.com/donho),是一个毕业于台湾淡江大学及巴黎第七大学的电脑工程师,作为一个台湾人,也是一个台独积极分子,侯今吾借助 Notepad++ 抹黑中国可谓由来已久。\n\n我也来说几句\n在这里我想说的是,Notepad++ 作为一款免费开源,深受国外编程爱好者赞扬,也为台湾开源界赢得好评,效率很高的文本编辑器,在早年间也是小编最喜欢常用的软件之一。但对于政见这件事情,小编觉得就像吃一道菜一样,你可以选择吃与不吃,不吃,你可以一笑而过,喜欢的人照常吃,与你无关,但你绝对不能吐一口脏东西上去。\n软件本身是没什么问题的,要说软件和作者之间的关系,那就是爱用不用的关系了。同类软件,我不喜欢你作者,当然就不用了,当然我不用也不会对软件发展有什么影响,不过我想说,这就像是去餐馆吃饭。对于顾客来说,他吃与不吃,不会影响服务员的工资。但对于服务员来说,至少不能让顾客觉得你讨厌。\n最后,有人说要抵制 Notepad++,但对我而言,小编是反对把开源与政治挂钩的,因此小编选择不用 Notepad++ —— 我有选择的权利,既然开源的编辑器那么多(我可以用 Sublime Text (虽然 Sublime Text 是非开源的),可以用 Visual Studio Code,可以用 Github Atom,也可以用 BowPad、Editra,甚至是国人开发的 Notepad--),我又何必选择一个带政治倾向自己又不喜欢的编辑器呢!', 'bodyHTML': '

Notepad++ 这片瓜田的瓜都吃了好几年了,作者却一直还在死性不改 。。。。。

\n

同样的 Notepad++ 在 GitHub 仓库 notepad-plus-plus 早已沦为反华辱华的垃圾场,群魔乱舞,简直惨不忍睹!

\n\n

say-no-to-Notepad++

\n

Add random characters

\n

Twitter:https://twitter.com/Notepad_plus/status/1618276938342359042
\nV2EX:https://www.v2ex.com/t/910777

\n

Twitter Notepad++

\n

Free Uyghur

\n

不知道大家有没有留意,前两天(2019 年 10 月 29)开源文本编辑器 Notepad++ 发布了最新的 \xa07.8.1\xa0 版本。

\n

然而,软件新版本发布后,在该版本中 Notepad++ 的作者同时附加了一篇名为《Notepad++ v7.8.1 : Free Uyghur》抹黑中国的文章,具体的内容请大家自行百度(图片是文章部分截图)。而且这已经不是 Notepad++ 第一次这么干了!
\nNotepad++ Free Uyghur

\n

Notepad++ 的 "Free Uyghur" 出来以后,Notepad++ 所在的 Github 瞬间被广大中国的开发者占领,他们用自己的方式进行了回击。小编也忍不住上去看一下,发现 \xa0GitHub 上面基本上都是骂 Notepad++ 作者的,不过也有少数支持作者。
\nnotepad-781-github-issue1

\n

notepad-781-github-issue2

\n

起底一下开发者

\n

后来查了一下,Notepad++ 的作者,原来名字叫做侯今吾(英语:DonHO,https://github.com/donho),是一个毕业于台湾淡江大学及巴黎第七大学的电脑工程师,作为一个台湾人,也是一个台独积极分子,侯今吾借助 Notepad++ 抹黑中国可谓由来已久。

\n

Notepad++ DonHO

\n

我也来说几句

\n

在这里我想说的是,Notepad++ 作为一款免费开源,深受国外编程爱好者赞扬,也为台湾开源界赢得好评,效率很高的文本编辑器,在早年间也是小编最喜欢常用的软件之一。但对于政见这件事情,小编觉得就像吃一道菜一样,你可以选择吃与不吃,不吃,你可以一笑而过,喜欢的人照常吃,与你无关,但你绝对不能吐一口脏东西上去。

\n

软件本身是没什么问题的,要说软件和作者之间的关系,那就是爱用不用的关系了。同类软件,我不喜欢你作者,当然就不用了,当然我不用也不会对软件发展有什么影响,不过我想说,这就像是去餐馆吃饭。对于顾客来说,他吃与不吃,不会影响服务员的工资。但对于服务员来说,至少不能让顾客觉得你讨厌。

\n

最后,有人说要抵制 Notepad++,但对我而言,小编是反对把开源与政治挂钩的,因此小编选择不用 Notepad++ —— 我有选择的权利,既然开源的编辑器那么多(我可以用 Sublime Text (虽然 Sublime Text 是非开源的),可以用 Visual Studio Code,可以用 Github Atom,也可以用 BowPadEditra,甚至是国人开发的 Notepad--),我又何必选择一个带政治倾向自己又不喜欢的编辑器呢!

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '2023 年 Galaxy 社区大会会议报告', 'number': 21, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/21', 'createdAt': '2023-11-23T01:47:28Z', 'lastEditedAt': '2023-12-01T05:36:10Z', 'updatedAt': '2024-01-04T05:45:31Z', 'body': '> 作者:Natalie Whitaker \r\n> 编译:[沈维燕](https://weiyan.cc) \r\n> 时间:2023-08-14 \r\n> 原文:[2023 Galaxy Community Conference Meeting Report](https://galaxyproject.org/blog/2023-08-14-gc-c2023-meeting-report/) \r\n\r\n\r\n\t\t\r\n## GCC 2023 会议纪要\r\n\r\n### 概述\r\n2023 年 Galaxy 社区会议(GCC2023)于7月10日至16日在澳大利亚昆士兰州布里斯班昆士兰科技大学举行。GCC 是 Galaxy 社区的年度会议,这是一个旨在在科学和技术层面展示过去一年内在 Galaxy 研究领域做出的令人惊叹的新工作,同时为与会者提供发现合作机会、加强联系、并开辟新的研究方向的大会。 GCC2023 由 Galaxy Australia 和 Australian BioCommons 主办,为期四天,包括了演讲、研讨会/培训、海报和演示等活动,还有三位主题演讲嘉宾和三天的协作节 (CoFest)。除了会议内容,整个 Galaxy 社区会议周还会举办网络交流和社交活动。总体而言,GCC2023 包括了 12.8 小时的长短演讲、37.5 小时的培训、3.3 小时的海报展示和演示,以及 10.6 小时的社交活动和交流。\r\n![GCC2023 Meeting Report Image1](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image1.png)\r\n\r\nGCC2023 共有 91 名现场参会者和 40 名虚拟参会者。来自 21 个不同国家的与会者出席了本次会议:澳大利亚、比利时、巴西、加拿大、捷克、丹麦、法国、德国、印度、爱尔兰、马耳他、摩洛哥、荷兰、新西兰、挪威、新加坡、韩国、斯里兰卡、瑞士、英国和美国(图1)。在总参会人数中,22.4% 是研究助理或技术人员,17.6% 是高级科学家或首席调查员,9.6% 是研究生,7.2% 是博士后,2.4% 是本科生,40% 是其他身份。\r\n\r\n
\r\n GCC2023 Meeting Report Image2\r\n Figure 1. Map of GCC2023 attendees’ countries of origin.\r\n
\r\n\r\n\r\n## 奖学金获得者\r\nGCC2023 非常感谢能够利用一位匿名捐赠者的资金提供现场和虚拟参会的奖学金。作为奖学金的一部分,受奖者被要求通过演讲、海报或二者兼有的方式参与会议。\r\n\r\n今年,一个现场奖学金授予了英国开放大学的一年级博士生 Marisa Loach(Twitter: @Marisa_Loach)。Marisa 进行了一次题为 “为什么使用 Galaxy?用户友好的生物信息学选项的初步结果” 的演讲并展示了一份海报。\r\n![GCC2023 Meeting Report Image3](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image3.png)\r\n\r\nGCC2023共颁发了六个虚拟奖学金。以下列出了每位受奖者及其角色、机构和对会议的贡献。\r\n\r\n### Coline Royaux\r\nTwitter: @ColineRoyaux\r\n\r\n研究生 (Graduate student)\r\n\r\n巴黎索邦大学,法国自然历史博物馆,法国 (Sorbonne University, French Natural History Museum, France)\r\n\r\n演讲标题 “Galaxy-E:基于生态学的 Galaxy 倡议,2022-2023 年更新!” \r\n\r\n### Vajiha Hussain\r\n高年级本科生 (Senior undergraduate student)\r\n\r\n印度维尼昂大学 (Vignan University, India)\r\n\r\n海报标题 “利用 RNASeq 分析识别棕榈蓟马中潜在的 GBNV 生物标志物”\r\n\r\n### Sudeepti Kulshrestha\r\n研究生 (Graduate student)\r\n\r\n印度阿米蒂大学 (Amity University, India)\r\n\r\n海报标题为“使用基于网络的方法探索 Vaginal Microbiome 和先兆子痫的关联”\r\n\r\n### Jonas Bucher\r\n研究生 (Graduate student)\r\n\r\n瑞士苏黎世联邦理工学院,苏黎世大学,瑞士 (Swiss Federal Institute of Technology in Zurich (ETH Zurich), University of Zurich, Switzerland)\r\n\r\n海报标题 “Methylator - DNA cytosine methylation pipeline”\r\n\r\n\r\n### Katarzyna Kamieniecka\r\nTwitter: @katemurat\r\n\r\n研究生 (Graduate student)\r\n\r\n英国布拉德福德大学 (University of Bradford, United Kingdom)\r\n\r\n海报标题 "Galaxy 中的 FAIR 数据管理"\r\n\r\n#### Taoufik Bensellak\r\n研究生 (Graduate student)\r\n\r\n英国利物浦大学 (University of Liverpool, United Kingdom)\r\n\r\n海报标题 “用于微阵列数据分析的 Galaxy 实例和工具”\r\n\r\n## 主讲嘉宾\r\nGCC2023 邀请了三位主题演讲嘉宾,分别就野生动物保护、结构生物学和生物安全等领域分享了他们的思考和研究成果。演讲者展示了他们团队如何通过使用 Galaxy 平台,以更易获取和可复现的方式完成工作。\r\n\r\n三位主题发言人分别发表了内容丰富的演讲,讨论了各自前瞻性研究领域的进展,重点关注开放存取端到端生物信息学 (open-access end-to-end bioinformatics)。Galaxy 在每位主题发言人的最新研究进展中都发挥了重要作用,Galaxy 开发人员和 Galaxy 社区能够亲眼目睹 Galaxy 对科学界的影响。此外,每位主题发言人都为 Galaxy 的未来提供了灵感,并有时间与平台发展轨迹背后的开发人员直接交流。\r\n\r\n### Carolyn Hogg, PhD (University of Sydney,悉尼大学)\r\n来自悉尼大学的 Carolyn Hogg 博士作为第一位主讲人拉开了 GCC2023 的序幕。霍格博士在 "拯救塔斯马尼亚袋獾计划 (Save the Tasmanian Devil Program)" 进行的研究中发挥了重要作用,此外还重点研究了其他澳大利亚物种,如橙腹鹦鹉、考拉、兔耳袋狸和袋鼠。她在 GCC2023 上的演讲题为 “走向无限和超越:结合基因组学和云技术来拯救我们的物种”,强调了自然资源保护主义者和基因组科学家之间合作研究的必要性。她的愿景是通过改变科学、管理和政策的整合方式,为澳大利亚创造保护遗产,而 Galaxy 的使用增强了她的这一愿景。通过使用像 Galaxy 这样的开源平台,Hogg 博士能够产生可重复的基因组科学,以帮助澳大利亚的物种保护和管理实践。\r\n![GCC2023 Meeting Report Image4](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image4.png)\r\n\r\n### Kate Michie, PhD (University of New South Wales,新南威尔士大学)\r\n来自新南威尔士大学的 Kate Michie 博士作为 GCC2023 的第二位主讲人发表了题为 “Alphafold2 和深度学习时代:结构生物学的最新进展” 的演讲。 Michie 博士在蛋白质结构生物学方面拥有二十多年的经验,并广泛使用 Alphafold2,并与众多研究人员密切合作,教他们如何使用这一强大的工具来推进他们的研究。在她的主题演讲中,Michie 博士呼吁关注 Galaxy 为结构生物学研究进展做好准备的迫切需要,这些进展肯定会伴随 Alphafold2 的巨大成功。 Michie 博士的演讲对 GCC2023 来说是一个有影响力的补充,因为 Galaxy 致力于保持竞争力并领先于社区的巨大研究需求。\r\n![GCC2023 Meeting Report Image5](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image5.png)\r\n\r\n### Roberto Barrero, PhD (Queensland University of Technology,昆士兰科技大学)\r\nGCC2023 的最后一位主讲人是来自昆士兰科技大学的 Roberto Barrero 博士。巴雷罗博士的演讲题为 “通过更快、更准确地诊断植物病毒和类病毒,改善植物行业获得新遗传学的机会”,重点讨论利用生物信息学解决农业、植物生物安全和人类健康方面的现实问题。最近,Barrero 博士在开发植物诊断工具包方面发挥了重要作用,该工具包可以在一次测试中准确检测一系列病毒和类病毒,并于 2018 年向他和他的团队授予生物安全影响奖。Barrero 博士的研究进展得到了 Galaxy 的支持通过 GA-VirReport 和高通量测序技术。访问开放式端到端生物信息学工作流程对于诊断植物病毒和类病毒至关重要,Galaxy 很高兴能在 GCC2023 上将这一主题置于前沿。\r\n![GCC2023 Meeting Report Image6](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image6.png)\r\n\r\n## 培训课程\r\n![GCC2023 Meeting Report Image7](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image7.png)\r\n培训是 Galaxy 社区的首要任务。让研究人员能够轻松学习使用该平台、如何进行新的分析或探索能够解决研究人员面临的实际需求的功能和工具,对于 Galaxy 的发展和可持续发展发挥了重要作用。本着这种精神,在 GCC2023 的三天里,共举办了 15 场不同的培训课程,供与会者与专家一起学习和实践生物信息学。专家包括主要研究员、Galaxy 开发人员、项目经理和 Galaxy 高级用户。培训课程主题多种多样,为 GCC2023 的所有与会者提供相关且实用的学习机会。从微生物学和人类遗传学到工作流程和工具开发,GCC2023 培训课程提供了扩大与会者特定研究兴趣和遇到新主题的机会。\r\n\r\n每节课将近三个小时,让学员有时间充分沉浸在教材中,与培训师和其他学员交流,并与来自不同背景的人交流经验和方法。\r\n\r\n## Birds of a Feather (BoF)\r\nBirds of a Feather (BoF) 会议是 GCC 期间的非正式聚会,参与者可以讨论感兴趣的话题。 BoF 每天在会议结束时举行,各小组分成焦点小组,与专家和其他与会者进行交流和讨论。\r\n\r\nGCC2023 期间,与会者有九种不同的机会参加 BoF。今年的 BoF 提出了各种主题,包括备受期待的 Galaxy 高级用户与开发人员对话的机会。此外,BoF 还提供了举办迷你社交活动的机会,例如棋盘游戏、串酒吧和澳大利亚布里斯班徒步之旅!\r\n\r\n## CoFest\r\nGCC2023 主会之后,举办了为期三天的协作节(CoFest)。 CoFest 是 Galaxy 成员的社区聚会,这些成员有兴趣为 Galaxy 的工具集、文档、培训材料、代码库以及扩展 Galaxy 生态系统的其他任何地方做出贡献。 CoFest 的目标是:\r\n\r\n1. 扩大贡献者社区。这次 CoFest 的首要目的是欢迎新的贡献者,帮助您学习资源并结识能够帮助您做出贡献的人。\r\n2. 扩大 Galaxy 生态系统。不仅仅是代码,而是整个生态系统。这包括培训、工具、最佳实践工作流程、文档、测试用例、翻译、基础设施,甚至代码。\r\n\r\nCoFest 的参与者围绕着共同的兴趣,讨论与这些兴趣相关的共同话题。这些群组在 CoFest 开始前、开始时和整个过程中形成,旨在相互之间保持流动和高度互动。今年的 CoFest 分为九大主题:前端、后端、社区、设计、工具、工作流程、培训、测试和辅助项目。由于 CoFest 在整个活动期间都在不断变化和构建,因此主题被进一步细分,重点关注以下主题:交互式工具;升级 Vue3 和上传功能;吸引和保留社区参与活动、管理和领导力;ChatGXY;实施 Galaxy 工具健康审计服务;以及 Simon 的数据俱乐部。\r\n\r\n## 社会事件\r\nGCC2023 希望将 Galaxy 社区的成员联系在一起,因此在整个会议期间举办了不同的社交活动。今年的 GCC2023 社交活动包括为会议拉开序幕的欢迎晚宴、由 Galaxy 社区成员主持的布里斯班徒步游、带有街机游戏的酒馆爬行、桌游之夜、会议晚宴,以及广受好评的 Lone Pine 考拉保护区之行!\r\n\r\n毫无疑问,Lone Pine 考拉保护区是今年社交活动的亮点!一大群 GCC2023 与会者参观了世界上最大的考拉保护区,度过了一个下午,与动物邂逅、野生动物表演,并了解一些澳大利亚最受欢迎的野生动物!\r\n![GCC2023 Meeting Report Image8](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image8.png)\r\n\r\n通过这些有组织的社交活动,Galaxy 社区的成员们在建立职业关系的同时,也建立了友谊。此外,许多社区成员还通过非组织活动,包括游览植物园、参观动物园医院和热带雨林,以及一日游等,彼此建立联系。\r\n\r\n请参阅附录一,了解今年社交活动的更多照片以及遇到的所有令人惊叹的澳大利亚动物!\r\n\r\n## 纪念 Simon Gladman\r\n### Simon 数据俱乐部\r\nSimon Gladman 是 GCC2023 的最初发起者和组织者,如果看到他的伴侣和孩子参加这次会议,他一定会感到非常自豪。Simon 获得了多项荣誉,他作为创新者、榜样、支持者和社区联系者的遗产将继续受到表彰,“星际数据委员会 (Intergalactic Data Commission)” 更名为 “Simon 数据俱乐部 (Simon’s Data Club)”,并在他的组织中获得年度奖项。姓名。\r\n![GCC2023 Meeting Report Image9](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image9.png)\r\n\r\n### Simon Gladman 旅行补助金\r\n已故西蒙·格拉德曼 (Simon Gladman) 对 Galaxy 的贡献将获得以他名字命名的年度奖项。 Galaxy Australia 才华横溢的技术主管和大家的伙伴 Simon 在 GCC2023 上受到了人们的深深怀念,人们对他表示了许多敬意。\r\n\r\nSimon 对 Galaxy 充满热情并与人交流,并且很高兴能够组织在澳大利亚举办的首届国际 Galaxy 社区会议 (GCC)。在 GCC2023 上,我们宣布了首届 Simon Gladman 旅行补助金,以此来庆祝他。每年将向参加 Galaxy 社区活动的澳大利亚公民颁发 5,000 澳元的补助金。\r\n\r\n如果您与 Simon 一样充满热情并希望为 Galaxy 做出贡献,我们鼓励您申请 Simon Gladman 旅行补助金。\r\n\r\n## 感言\r\nGalaxy 执行董事会成员 Michael Schatz 是约翰·霍普金斯大学计算机科学和生物学的彭博杰出教授,他很高兴地看到:\r\n\r\n> *"The keynotes really highlighted how Galaxy enables cutting edge science.”*\r\n> *“主题演讲真正强调了 Galaxy 如何实现尖端科学。”*\r\n\r\n来自 BioCommons、昆士兰网络基础设施基金会 (QCIF)、昆士兰大学、墨尔本生物信息学和 AARNet 的 Galaxy Australia 团队成员发表了从监测工具健康状况到开发最近发布的 Galaxy Australia 基因组实验室等主题。澳大利亚银河服务项目负责人 Gareth Price 博士表示:\r\n\r\n> *“There was a fantastic exchange between our team and international colleagues and wonderful opportunities to engage with the global Galaxy community. GCC was an exhilarating experience, and it was inspiring to be surrounded by like-minded people. The team left full of energy to keep improving Galaxy Australia and strengthen their collaborations with the wider Galaxy community.”*\r\n> *“我们的团队与国际同事之间进行了精彩的交流,并有绝佳的机会与全球 Galaxy 社区互动。 GCC 是一次令人兴奋的经历,周围都是志趣相投的人,这很鼓舞人心。该团队充满活力地继续改进 Galaxy Australia,并加强与更广泛的 Galaxy 社区的合作。”*\r\n\r\n虽然我们是在昆士兰科技大学 (QUT) 的 The Cube 一流设施中举办的,但远程参与的能力是举办真正国际会议的关键因素。尽管 Amrita 大学系统基因组学首席科学家 Prash Suravajhala 博士是 GCC2023 组委会成员,但他无法从印度出发,但他:\r\n\r\n> *“Very excited and happy to be a part of GCC2023 virtually. We witnessed scintillating talks and brainstorming sessions, and the virtual attendance was a treat. This was a cherishing moment for me as I guzzled the talks from early morning India time! It has created a great camaraderie."*\r\n> *“能够以虚拟方式参加 GCC2023 感到非常兴奋和高兴。我们目睹了精彩的演讲和头脑风暴会议,虚拟出席是一种享受。这对我来说是一个珍贵的时刻,因为我沉迷于印度时间清晨的演讲!它创造了伟大的友情。"*\r\n\r\n## Recognition\r\n特别感谢 GCC2023 的赞助商:\r\n\r\n### 白金赞助商\r\nBizData ()\r\n\r\n### 银牌赞助商\r\nLimagrain ()\r\n\r\nGalaxyWorks ()\r\n\r\n### 铜牌赞助商\r\nGIGA Science ()\r\n\r\n\r\n非常感谢所有使 GCC2023 取得成功的个人:\r\n\r\n### 组织和科学委员会\r\nAndrew Lonie\r\n\r\nChristina Hall\r\n\r\nEnis Afgan\r\n\r\nGareth Price\r\n\r\nJenn Vessio\r\n\r\nMargita Jadan\r\n\r\nPrash Suravajhala\r\n\r\nRoberto Barrero Gumiel\r\n\r\nRoss Lazarus\r\n\r\nAssunta DeSanto\r\n\r\nNatalie Whitaker\r\n\r\nSimon Gladman\r\n\r\nClaudia Melogno de Sandoval \r\n\r\n\r\n### 培训协调员\r\nAssunta DeSanto\r\n\r\nIgor Makunin\r\n\r\nMark Crowe\r\n\r\n\r\n### 在线支持\r\nMelissa Burke\r\n\r\nPatrick Capon\r\n\r\n\r\n### 科学计划成员\r\nAndrew Lonie\r\n\r\nAnne Claire Fouilloux\r\n\r\nAnna Syme\r\n\r\nAnshu Bhardwaj\r\n\r\nBérénice Batut\r\n\r\nBryan Raubenolt\r\n\r\nCameron Hyde\r\n\r\nCatherine Bromhead\r\n\r\nClare Sloggett\r\n\r\nCristóbal Gallardo\r\n\r\nDan Blankenberg\r\n\r\nDavor Davidović\r\n\r\nEnis Afgan\r\n\r\nFrederik Coppens\r\n\r\nHans-Rudolf Hotz\r\n\r\nIvan Jakovlić\r\n\r\nJeremy Goecks\r\n\r\nJustin Lee\r\n\r\nMargita Jadan\r\n\r\nMaria Doyle\r\n\r\nMatthias Bernt\r\n\r\nNatalie Kucher\r\n\r\nNicola Soranzo\r\n\r\nNuwan Goonasekera\r\n\r\nPeter van Heusden\r\n\r\nRalf Weber\r\n\r\nRoss Lazarus\r\n\r\nSoyean Kim\r\n\r\nThomas Harrop\r\n\r\nTimothy Griffin\r\n\r\nTyler Collins\r\n\r\nWendi Bacon\r\n\r\nYvan Le Bras\r\n\r\n\r\n### 联合节主办方\r\nCameron Hyde\r\n\r\n## *附录一*\r\n\r\n![GCC2023 Meeting Report Image10](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image10.png)\r\n\r\n![GCC2023 Meeting Report Image11](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image11.png)\r\n\r\n![GCC2023 Meeting Report Image12](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image12.png)\r\n\r\n![GCC2023 Meeting Report Image13](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image13.png)\r\n\r\n![GCC2023 Meeting Report Image14](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/GCC2023-Meeting-Report-Image14.png)', 'bodyText': '作者:Natalie Whitaker\n编译:沈维燕\n时间:2023-08-14\n原文:2023 Galaxy Community Conference Meeting Report\n\n\nGCC 2023 会议纪要\n概述\n2023 年 Galaxy 社区会议(GCC2023)于7月10日至16日在澳大利亚昆士兰州布里斯班昆士兰科技大学举行。GCC 是 Galaxy 社区的年度会议,这是一个旨在在科学和技术层面展示过去一年内在 Galaxy 研究领域做出的令人惊叹的新工作,同时为与会者提供发现合作机会、加强联系、并开辟新的研究方向的大会。 GCC2023 由 Galaxy Australia 和 Australian BioCommons 主办,为期四天,包括了演讲、研讨会/培训、海报和演示等活动,还有三位主题演讲嘉宾和三天的协作节 (CoFest)。除了会议内容,整个 Galaxy 社区会议周还会举办网络交流和社交活动。总体而言,GCC2023 包括了 12.8 小时的长短演讲、37.5 小时的培训、3.3 小时的海报展示和演示,以及 10.6 小时的社交活动和交流。\n\nGCC2023 共有 91 名现场参会者和 40 名虚拟参会者。来自 21 个不同国家的与会者出席了本次会议:澳大利亚、比利时、巴西、加拿大、捷克、丹麦、法国、德国、印度、爱尔兰、马耳他、摩洛哥、荷兰、新西兰、挪威、新加坡、韩国、斯里兰卡、瑞士、英国和美国(图1)。在总参会人数中,22.4% 是研究助理或技术人员,17.6% 是高级科学家或首席调查员,9.6% 是研究生,7.2% 是博士后,2.4% 是本科生,40% 是其他身份。\n\n \n Figure 1. Map of GCC2023 attendees’ countries of origin.\n\n奖学金获得者\nGCC2023 非常感谢能够利用一位匿名捐赠者的资金提供现场和虚拟参会的奖学金。作为奖学金的一部分,受奖者被要求通过演讲、海报或二者兼有的方式参与会议。\n今年,一个现场奖学金授予了英国开放大学的一年级博士生 Marisa Loach(Twitter: @Marisa_Loach)。Marisa 进行了一次题为 “为什么使用 Galaxy?用户友好的生物信息学选项的初步结果” 的演讲并展示了一份海报。\n\nGCC2023共颁发了六个虚拟奖学金。以下列出了每位受奖者及其角色、机构和对会议的贡献。\nColine Royaux\nTwitter: @ColineRoyaux\n研究生 (Graduate student)\n巴黎索邦大学,法国自然历史博物馆,法国 (Sorbonne University, French Natural History Museum, France)\n演讲标题 “Galaxy-E:基于生态学的 Galaxy 倡议,2022-2023 年更新!”\nVajiha Hussain\n高年级本科生 (Senior undergraduate student)\n印度维尼昂大学 (Vignan University, India)\n海报标题 “利用 RNASeq 分析识别棕榈蓟马中潜在的 GBNV 生物标志物”\nSudeepti Kulshrestha\n研究生 (Graduate student)\n印度阿米蒂大学 (Amity University, India)\n海报标题为“使用基于网络的方法探索 Vaginal Microbiome 和先兆子痫的关联”\nJonas Bucher\n研究生 (Graduate student)\n瑞士苏黎世联邦理工学院,苏黎世大学,瑞士 (Swiss Federal Institute of Technology in Zurich (ETH Zurich), University of Zurich, Switzerland)\n海报标题 “Methylator - DNA cytosine methylation pipeline”\nKatarzyna Kamieniecka\nTwitter: @katemurat\n研究生 (Graduate student)\n英国布拉德福德大学 (University of Bradford, United Kingdom)\n海报标题 "Galaxy 中的 FAIR 数据管理"\nTaoufik Bensellak\n研究生 (Graduate student)\n英国利物浦大学 (University of Liverpool, United Kingdom)\n海报标题 “用于微阵列数据分析的 Galaxy 实例和工具”\n主讲嘉宾\nGCC2023 邀请了三位主题演讲嘉宾,分别就野生动物保护、结构生物学和生物安全等领域分享了他们的思考和研究成果。演讲者展示了他们团队如何通过使用 Galaxy 平台,以更易获取和可复现的方式完成工作。\n三位主题发言人分别发表了内容丰富的演讲,讨论了各自前瞻性研究领域的进展,重点关注开放存取端到端生物信息学 (open-access end-to-end bioinformatics)。Galaxy 在每位主题发言人的最新研究进展中都发挥了重要作用,Galaxy 开发人员和 Galaxy 社区能够亲眼目睹 Galaxy 对科学界的影响。此外,每位主题发言人都为 Galaxy 的未来提供了灵感,并有时间与平台发展轨迹背后的开发人员直接交流。\nCarolyn Hogg, PhD (University of Sydney,悉尼大学)\n来自悉尼大学的 Carolyn Hogg 博士作为第一位主讲人拉开了 GCC2023 的序幕。霍格博士在 "拯救塔斯马尼亚袋獾计划 (Save the Tasmanian Devil Program)" 进行的研究中发挥了重要作用,此外还重点研究了其他澳大利亚物种,如橙腹鹦鹉、考拉、兔耳袋狸和袋鼠。她在 GCC2023 上的演讲题为 “走向无限和超越:结合基因组学和云技术来拯救我们的物种”,强调了自然资源保护主义者和基因组科学家之间合作研究的必要性。她的愿景是通过改变科学、管理和政策的整合方式,为澳大利亚创造保护遗产,而 Galaxy 的使用增强了她的这一愿景。通过使用像 Galaxy 这样的开源平台,Hogg 博士能够产生可重复的基因组科学,以帮助澳大利亚的物种保护和管理实践。\n\nKate Michie, PhD (University of New South Wales,新南威尔士大学)\n来自新南威尔士大学的 Kate Michie 博士作为 GCC2023 的第二位主讲人发表了题为 “Alphafold2 和深度学习时代:结构生物学的最新进展” 的演讲。 Michie 博士在蛋白质结构生物学方面拥有二十多年的经验,并广泛使用 Alphafold2,并与众多研究人员密切合作,教他们如何使用这一强大的工具来推进他们的研究。在她的主题演讲中,Michie 博士呼吁关注 Galaxy 为结构生物学研究进展做好准备的迫切需要,这些进展肯定会伴随 Alphafold2 的巨大成功。 Michie 博士的演讲对 GCC2023 来说是一个有影响力的补充,因为 Galaxy 致力于保持竞争力并领先于社区的巨大研究需求。\n\nRoberto Barrero, PhD (Queensland University of Technology,昆士兰科技大学)\nGCC2023 的最后一位主讲人是来自昆士兰科技大学的 Roberto Barrero 博士。巴雷罗博士的演讲题为 “通过更快、更准确地诊断植物病毒和类病毒,改善植物行业获得新遗传学的机会”,重点讨论利用生物信息学解决农业、植物生物安全和人类健康方面的现实问题。最近,Barrero 博士在开发植物诊断工具包方面发挥了重要作用,该工具包可以在一次测试中准确检测一系列病毒和类病毒,并于 2018 年向他和他的团队授予生物安全影响奖。Barrero 博士的研究进展得到了 Galaxy 的支持通过 GA-VirReport 和高通量测序技术。访问开放式端到端生物信息学工作流程对于诊断植物病毒和类病毒至关重要,Galaxy 很高兴能在 GCC2023 上将这一主题置于前沿。\n\n培训课程\n\n培训是 Galaxy 社区的首要任务。让研究人员能够轻松学习使用该平台、如何进行新的分析或探索能够解决研究人员面临的实际需求的功能和工具,对于 Galaxy 的发展和可持续发展发挥了重要作用。本着这种精神,在 GCC2023 的三天里,共举办了 15 场不同的培训课程,供与会者与专家一起学习和实践生物信息学。专家包括主要研究员、Galaxy 开发人员、项目经理和 Galaxy 高级用户。培训课程主题多种多样,为 GCC2023 的所有与会者提供相关且实用的学习机会。从微生物学和人类遗传学到工作流程和工具开发,GCC2023 培训课程提供了扩大与会者特定研究兴趣和遇到新主题的机会。\n每节课将近三个小时,让学员有时间充分沉浸在教材中,与培训师和其他学员交流,并与来自不同背景的人交流经验和方法。\nBirds of a Feather (BoF)\nBirds of a Feather (BoF) 会议是 GCC 期间的非正式聚会,参与者可以讨论感兴趣的话题。 BoF 每天在会议结束时举行,各小组分成焦点小组,与专家和其他与会者进行交流和讨论。\nGCC2023 期间,与会者有九种不同的机会参加 BoF。今年的 BoF 提出了各种主题,包括备受期待的 Galaxy 高级用户与开发人员对话的机会。此外,BoF 还提供了举办迷你社交活动的机会,例如棋盘游戏、串酒吧和澳大利亚布里斯班徒步之旅!\nCoFest\nGCC2023 主会之后,举办了为期三天的协作节(CoFest)。 CoFest 是 Galaxy 成员的社区聚会,这些成员有兴趣为 Galaxy 的工具集、文档、培训材料、代码库以及扩展 Galaxy 生态系统的其他任何地方做出贡献。 CoFest 的目标是:\n\n扩大贡献者社区。这次 CoFest 的首要目的是欢迎新的贡献者,帮助您学习资源并结识能够帮助您做出贡献的人。\n扩大 Galaxy 生态系统。不仅仅是代码,而是整个生态系统。这包括培训、工具、最佳实践工作流程、文档、测试用例、翻译、基础设施,甚至代码。\n\nCoFest 的参与者围绕着共同的兴趣,讨论与这些兴趣相关的共同话题。这些群组在 CoFest 开始前、开始时和整个过程中形成,旨在相互之间保持流动和高度互动。今年的 CoFest 分为九大主题:前端、后端、社区、设计、工具、工作流程、培训、测试和辅助项目。由于 CoFest 在整个活动期间都在不断变化和构建,因此主题被进一步细分,重点关注以下主题:交互式工具;升级 Vue3 和上传功能;吸引和保留社区参与活动、管理和领导力;ChatGXY;实施 Galaxy 工具健康审计服务;以及 Simon 的数据俱乐部。\n社会事件\nGCC2023 希望将 Galaxy 社区的成员联系在一起,因此在整个会议期间举办了不同的社交活动。今年的 GCC2023 社交活动包括为会议拉开序幕的欢迎晚宴、由 Galaxy 社区成员主持的布里斯班徒步游、带有街机游戏的酒馆爬行、桌游之夜、会议晚宴,以及广受好评的 Lone Pine 考拉保护区之行!\n毫无疑问,Lone Pine 考拉保护区是今年社交活动的亮点!一大群 GCC2023 与会者参观了世界上最大的考拉保护区,度过了一个下午,与动物邂逅、野生动物表演,并了解一些澳大利亚最受欢迎的野生动物!\n\n通过这些有组织的社交活动,Galaxy 社区的成员们在建立职业关系的同时,也建立了友谊。此外,许多社区成员还通过非组织活动,包括游览植物园、参观动物园医院和热带雨林,以及一日游等,彼此建立联系。\n请参阅附录一,了解今年社交活动的更多照片以及遇到的所有令人惊叹的澳大利亚动物!\n纪念 Simon Gladman\nSimon 数据俱乐部\nSimon Gladman 是 GCC2023 的最初发起者和组织者,如果看到他的伴侣和孩子参加这次会议,他一定会感到非常自豪。Simon 获得了多项荣誉,他作为创新者、榜样、支持者和社区联系者的遗产将继续受到表彰,“星际数据委员会 (Intergalactic Data Commission)” 更名为 “Simon 数据俱乐部 (Simon’s Data Club)”,并在他的组织中获得年度奖项。姓名。\n\nSimon Gladman 旅行补助金\n已故西蒙·格拉德曼 (Simon Gladman) 对 Galaxy 的贡献将获得以他名字命名的年度奖项。 Galaxy Australia 才华横溢的技术主管和大家的伙伴 Simon 在 GCC2023 上受到了人们的深深怀念,人们对他表示了许多敬意。\nSimon 对 Galaxy 充满热情并与人交流,并且很高兴能够组织在澳大利亚举办的首届国际 Galaxy 社区会议 (GCC)。在 GCC2023 上,我们宣布了首届 Simon Gladman 旅行补助金,以此来庆祝他。每年将向参加 Galaxy 社区活动的澳大利亚公民颁发 5,000 澳元的补助金。\n如果您与 Simon 一样充满热情并希望为 Galaxy 做出贡献,我们鼓励您申请 Simon Gladman 旅行补助金。\n感言\nGalaxy 执行董事会成员 Michael Schatz 是约翰·霍普金斯大学计算机科学和生物学的彭博杰出教授,他很高兴地看到:\n\n"The keynotes really highlighted how Galaxy enables cutting edge science.”\n“主题演讲真正强调了 Galaxy 如何实现尖端科学。”\n\n来自 BioCommons、昆士兰网络基础设施基金会 (QCIF)、昆士兰大学、墨尔本生物信息学和 AARNet 的 Galaxy Australia 团队成员发表了从监测工具健康状况到开发最近发布的 Galaxy Australia 基因组实验室等主题。澳大利亚银河服务项目负责人 Gareth Price 博士表示:\n\n“There was a fantastic exchange between our team and international colleagues and wonderful opportunities to engage with the global Galaxy community. GCC was an exhilarating experience, and it was inspiring to be surrounded by like-minded people. The team left full of energy to keep improving Galaxy Australia and strengthen their collaborations with the wider Galaxy community.”\n“我们的团队与国际同事之间进行了精彩的交流,并有绝佳的机会与全球 Galaxy 社区互动。 GCC 是一次令人兴奋的经历,周围都是志趣相投的人,这很鼓舞人心。该团队充满活力地继续改进 Galaxy Australia,并加强与更广泛的 Galaxy 社区的合作。”\n\n虽然我们是在昆士兰科技大学 (QUT) 的 The Cube 一流设施中举办的,但远程参与的能力是举办真正国际会议的关键因素。尽管 Amrita 大学系统基因组学首席科学家 Prash Suravajhala 博士是 GCC2023 组委会成员,但他无法从印度出发,但他:\n\n“Very excited and happy to be a part of GCC2023 virtually. We witnessed scintillating talks and brainstorming sessions, and the virtual attendance was a treat. This was a cherishing moment for me as I guzzled the talks from early morning India time! It has created a great camaraderie."\n“能够以虚拟方式参加 GCC2023 感到非常兴奋和高兴。我们目睹了精彩的演讲和头脑风暴会议,虚拟出席是一种享受。这对我来说是一个珍贵的时刻,因为我沉迷于印度时间清晨的演讲!它创造了伟大的友情。"\n\nRecognition\n特别感谢 GCC2023 的赞助商:\n白金赞助商\nBizData (https://www.bizdata.com.au/)\n银牌赞助商\nLimagrain (https://www.limagrain.com/en)\nGalaxyWorks (https://galaxyworks.io/)\n铜牌赞助商\nGIGA Science (https://academic.oup.com/gigascience?login=false)\n非常感谢所有使 GCC2023 取得成功的个人:\n组织和科学委员会\nAndrew Lonie\nChristina Hall\nEnis Afgan\nGareth Price\nJenn Vessio\nMargita Jadan\nPrash Suravajhala\nRoberto Barrero Gumiel\nRoss Lazarus\nAssunta DeSanto\nNatalie Whitaker\nSimon Gladman\nClaudia Melogno de Sandoval\n培训协调员\nAssunta DeSanto\nIgor Makunin\nMark Crowe\n在线支持\nMelissa Burke\nPatrick Capon\n科学计划成员\nAndrew Lonie\nAnne Claire Fouilloux\nAnna Syme\nAnshu Bhardwaj\nBérénice Batut\nBryan Raubenolt\nCameron Hyde\nCatherine Bromhead\nClare Sloggett\nCristóbal Gallardo\nDan Blankenberg\nDavor Davidović\nEnis Afgan\nFrederik Coppens\nHans-Rudolf Hotz\nIvan Jakovlić\nJeremy Goecks\nJustin Lee\nMargita Jadan\nMaria Doyle\nMatthias Bernt\nNatalie Kucher\nNicola Soranzo\nNuwan Goonasekera\nPeter van Heusden\nRalf Weber\nRoss Lazarus\nSoyean Kim\nThomas Harrop\nTimothy Griffin\nTyler Collins\nWendi Bacon\nYvan Le Bras\n联合节主办方\nCameron Hyde\n附录一', 'bodyHTML': '
\n

作者:Natalie Whitaker
\n编译:沈维燕
\n时间:2023-08-14
\n原文:2023 Galaxy Community Conference Meeting Report

\n
\n\n

GCC 2023 会议纪要

\n

概述

\n

2023 年 Galaxy 社区会议(GCC2023)于7月10日至16日在澳大利亚昆士兰州布里斯班昆士兰科技大学举行。GCC 是 Galaxy 社区的年度会议,这是一个旨在在科学和技术层面展示过去一年内在 Galaxy 研究领域做出的令人惊叹的新工作,同时为与会者提供发现合作机会、加强联系、并开辟新的研究方向的大会。 GCC2023 由 Galaxy Australia 和 Australian BioCommons 主办,为期四天,包括了演讲、研讨会/培训、海报和演示等活动,还有三位主题演讲嘉宾和三天的协作节 (CoFest)。除了会议内容,整个 Galaxy 社区会议周还会举办网络交流和社交活动。总体而言,GCC2023 包括了 12.8 小时的长短演讲、37.5 小时的培训、3.3 小时的海报展示和演示,以及 10.6 小时的社交活动和交流。
\nGCC2023 Meeting Report Image1

\n

GCC2023 共有 91 名现场参会者和 40 名虚拟参会者。来自 21 个不同国家的与会者出席了本次会议:澳大利亚、比利时、巴西、加拿大、捷克、丹麦、法国、德国、印度、爱尔兰、马耳他、摩洛哥、荷兰、新西兰、挪威、新加坡、韩国、斯里兰卡、瑞士、英国和美国(图1)。在总参会人数中,22.4% 是研究助理或技术人员,17.6% 是高级科学家或首席调查员,9.6% 是研究生,7.2% 是博士后,2.4% 是本科生,40% 是其他身份。

\n
\n GCC2023 Meeting Report Image2\n Figure 1. Map of GCC2023 attendees’ countries of origin.\n
\n

奖学金获得者

\n

GCC2023 非常感谢能够利用一位匿名捐赠者的资金提供现场和虚拟参会的奖学金。作为奖学金的一部分,受奖者被要求通过演讲、海报或二者兼有的方式参与会议。

\n

今年,一个现场奖学金授予了英国开放大学的一年级博士生 Marisa Loach(Twitter: @Marisa_Loach)。Marisa 进行了一次题为 “为什么使用 Galaxy?用户友好的生物信息学选项的初步结果” 的演讲并展示了一份海报。
\nGCC2023 Meeting Report Image3

\n

GCC2023共颁发了六个虚拟奖学金。以下列出了每位受奖者及其角色、机构和对会议的贡献。

\n

Coline Royaux

\n

Twitter: @ColineRoyaux

\n

研究生 (Graduate student)

\n

巴黎索邦大学,法国自然历史博物馆,法国 (Sorbonne University, French Natural History Museum, France)

\n

演讲标题 “Galaxy-E:基于生态学的 Galaxy 倡议,2022-2023 年更新!”

\n

Vajiha Hussain

\n

高年级本科生 (Senior undergraduate student)

\n

印度维尼昂大学 (Vignan University, India)

\n

海报标题 “利用 RNASeq 分析识别棕榈蓟马中潜在的 GBNV 生物标志物”

\n

Sudeepti Kulshrestha

\n

研究生 (Graduate student)

\n

印度阿米蒂大学 (Amity University, India)

\n

海报标题为“使用基于网络的方法探索 Vaginal Microbiome 和先兆子痫的关联”

\n

Jonas Bucher

\n

研究生 (Graduate student)

\n

瑞士苏黎世联邦理工学院,苏黎世大学,瑞士 (Swiss Federal Institute of Technology in Zurich (ETH Zurich), University of Zurich, Switzerland)

\n

海报标题 “Methylator - DNA cytosine methylation pipeline”

\n

Katarzyna Kamieniecka

\n

Twitter: @katemurat

\n

研究生 (Graduate student)

\n

英国布拉德福德大学 (University of Bradford, United Kingdom)

\n

海报标题 "Galaxy 中的 FAIR 数据管理"

\n

Taoufik Bensellak

\n

研究生 (Graduate student)

\n

英国利物浦大学 (University of Liverpool, United Kingdom)

\n

海报标题 “用于微阵列数据分析的 Galaxy 实例和工具”

\n

主讲嘉宾

\n

GCC2023 邀请了三位主题演讲嘉宾,分别就野生动物保护、结构生物学和生物安全等领域分享了他们的思考和研究成果。演讲者展示了他们团队如何通过使用 Galaxy 平台,以更易获取和可复现的方式完成工作。

\n

三位主题发言人分别发表了内容丰富的演讲,讨论了各自前瞻性研究领域的进展,重点关注开放存取端到端生物信息学 (open-access end-to-end bioinformatics)。Galaxy 在每位主题发言人的最新研究进展中都发挥了重要作用,Galaxy 开发人员和 Galaxy 社区能够亲眼目睹 Galaxy 对科学界的影响。此外,每位主题发言人都为 Galaxy 的未来提供了灵感,并有时间与平台发展轨迹背后的开发人员直接交流。

\n

Carolyn Hogg, PhD (University of Sydney,悉尼大学)

\n

来自悉尼大学的 Carolyn Hogg 博士作为第一位主讲人拉开了 GCC2023 的序幕。霍格博士在 "拯救塔斯马尼亚袋獾计划 (Save the Tasmanian Devil Program)" 进行的研究中发挥了重要作用,此外还重点研究了其他澳大利亚物种,如橙腹鹦鹉、考拉、兔耳袋狸和袋鼠。她在 GCC2023 上的演讲题为 “走向无限和超越:结合基因组学和云技术来拯救我们的物种”,强调了自然资源保护主义者和基因组科学家之间合作研究的必要性。她的愿景是通过改变科学、管理和政策的整合方式,为澳大利亚创造保护遗产,而 Galaxy 的使用增强了她的这一愿景。通过使用像 Galaxy 这样的开源平台,Hogg 博士能够产生可重复的基因组科学,以帮助澳大利亚的物种保护和管理实践。
\nGCC2023 Meeting Report Image4

\n

Kate Michie, PhD (University of New South Wales,新南威尔士大学)

\n

来自新南威尔士大学的 Kate Michie 博士作为 GCC2023 的第二位主讲人发表了题为 “Alphafold2 和深度学习时代:结构生物学的最新进展” 的演讲。 Michie 博士在蛋白质结构生物学方面拥有二十多年的经验,并广泛使用 Alphafold2,并与众多研究人员密切合作,教他们如何使用这一强大的工具来推进他们的研究。在她的主题演讲中,Michie 博士呼吁关注 Galaxy 为结构生物学研究进展做好准备的迫切需要,这些进展肯定会伴随 Alphafold2 的巨大成功。 Michie 博士的演讲对 GCC2023 来说是一个有影响力的补充,因为 Galaxy 致力于保持竞争力并领先于社区的巨大研究需求。
\nGCC2023 Meeting Report Image5

\n

Roberto Barrero, PhD (Queensland University of Technology,昆士兰科技大学)

\n

GCC2023 的最后一位主讲人是来自昆士兰科技大学的 Roberto Barrero 博士。巴雷罗博士的演讲题为 “通过更快、更准确地诊断植物病毒和类病毒,改善植物行业获得新遗传学的机会”,重点讨论利用生物信息学解决农业、植物生物安全和人类健康方面的现实问题。最近,Barrero 博士在开发植物诊断工具包方面发挥了重要作用,该工具包可以在一次测试中准确检测一系列病毒和类病毒,并于 2018 年向他和他的团队授予生物安全影响奖。Barrero 博士的研究进展得到了 Galaxy 的支持通过 GA-VirReport 和高通量测序技术。访问开放式端到端生物信息学工作流程对于诊断植物病毒和类病毒至关重要,Galaxy 很高兴能在 GCC2023 上将这一主题置于前沿。
\nGCC2023 Meeting Report Image6

\n

培训课程

\n

GCC2023 Meeting Report Image7
\n培训是 Galaxy 社区的首要任务。让研究人员能够轻松学习使用该平台、如何进行新的分析或探索能够解决研究人员面临的实际需求的功能和工具,对于 Galaxy 的发展和可持续发展发挥了重要作用。本着这种精神,在 GCC2023 的三天里,共举办了 15 场不同的培训课程,供与会者与专家一起学习和实践生物信息学。专家包括主要研究员、Galaxy 开发人员、项目经理和 Galaxy 高级用户。培训课程主题多种多样,为 GCC2023 的所有与会者提供相关且实用的学习机会。从微生物学和人类遗传学到工作流程和工具开发,GCC2023 培训课程提供了扩大与会者特定研究兴趣和遇到新主题的机会。

\n

每节课将近三个小时,让学员有时间充分沉浸在教材中,与培训师和其他学员交流,并与来自不同背景的人交流经验和方法。

\n

Birds of a Feather (BoF)

\n

Birds of a Feather (BoF) 会议是 GCC 期间的非正式聚会,参与者可以讨论感兴趣的话题。 BoF 每天在会议结束时举行,各小组分成焦点小组,与专家和其他与会者进行交流和讨论。

\n

GCC2023 期间,与会者有九种不同的机会参加 BoF。今年的 BoF 提出了各种主题,包括备受期待的 Galaxy 高级用户与开发人员对话的机会。此外,BoF 还提供了举办迷你社交活动的机会,例如棋盘游戏、串酒吧和澳大利亚布里斯班徒步之旅!

\n

CoFest

\n

GCC2023 主会之后,举办了为期三天的协作节(CoFest)。 CoFest 是 Galaxy 成员的社区聚会,这些成员有兴趣为 Galaxy 的工具集、文档、培训材料、代码库以及扩展 Galaxy 生态系统的其他任何地方做出贡献。 CoFest 的目标是:

\n
    \n
  1. 扩大贡献者社区。这次 CoFest 的首要目的是欢迎新的贡献者,帮助您学习资源并结识能够帮助您做出贡献的人。
  2. \n
  3. 扩大 Galaxy 生态系统。不仅仅是代码,而是整个生态系统。这包括培训、工具、最佳实践工作流程、文档、测试用例、翻译、基础设施,甚至代码。
  4. \n
\n

CoFest 的参与者围绕着共同的兴趣,讨论与这些兴趣相关的共同话题。这些群组在 CoFest 开始前、开始时和整个过程中形成,旨在相互之间保持流动和高度互动。今年的 CoFest 分为九大主题:前端、后端、社区、设计、工具、工作流程、培训、测试和辅助项目。由于 CoFest 在整个活动期间都在不断变化和构建,因此主题被进一步细分,重点关注以下主题:交互式工具;升级 Vue3 和上传功能;吸引和保留社区参与活动、管理和领导力;ChatGXY;实施 Galaxy 工具健康审计服务;以及 Simon 的数据俱乐部。

\n

社会事件

\n

GCC2023 希望将 Galaxy 社区的成员联系在一起,因此在整个会议期间举办了不同的社交活动。今年的 GCC2023 社交活动包括为会议拉开序幕的欢迎晚宴、由 Galaxy 社区成员主持的布里斯班徒步游、带有街机游戏的酒馆爬行、桌游之夜、会议晚宴,以及广受好评的 Lone Pine 考拉保护区之行!

\n

毫无疑问,Lone Pine 考拉保护区是今年社交活动的亮点!一大群 GCC2023 与会者参观了世界上最大的考拉保护区,度过了一个下午,与动物邂逅、野生动物表演,并了解一些澳大利亚最受欢迎的野生动物!
\nGCC2023 Meeting Report Image8

\n

通过这些有组织的社交活动,Galaxy 社区的成员们在建立职业关系的同时,也建立了友谊。此外,许多社区成员还通过非组织活动,包括游览植物园、参观动物园医院和热带雨林,以及一日游等,彼此建立联系。

\n

请参阅附录一,了解今年社交活动的更多照片以及遇到的所有令人惊叹的澳大利亚动物!

\n

纪念 Simon Gladman

\n

Simon 数据俱乐部

\n

Simon Gladman 是 GCC2023 的最初发起者和组织者,如果看到他的伴侣和孩子参加这次会议,他一定会感到非常自豪。Simon 获得了多项荣誉,他作为创新者、榜样、支持者和社区联系者的遗产将继续受到表彰,“星际数据委员会 (Intergalactic Data Commission)” 更名为 “Simon 数据俱乐部 (Simon’s Data Club)”,并在他的组织中获得年度奖项。姓名。
\nGCC2023 Meeting Report Image9

\n

Simon Gladman 旅行补助金

\n

已故西蒙·格拉德曼 (Simon Gladman) 对 Galaxy 的贡献将获得以他名字命名的年度奖项。 Galaxy Australia 才华横溢的技术主管和大家的伙伴 Simon 在 GCC2023 上受到了人们的深深怀念,人们对他表示了许多敬意。

\n

Simon 对 Galaxy 充满热情并与人交流,并且很高兴能够组织在澳大利亚举办的首届国际 Galaxy 社区会议 (GCC)。在 GCC2023 上,我们宣布了首届 Simon Gladman 旅行补助金,以此来庆祝他。每年将向参加 Galaxy 社区活动的澳大利亚公民颁发 5,000 澳元的补助金。

\n

如果您与 Simon 一样充满热情并希望为 Galaxy 做出贡献,我们鼓励您申请 Simon Gladman 旅行补助金。

\n

感言

\n

Galaxy 执行董事会成员 Michael Schatz 是约翰·霍普金斯大学计算机科学和生物学的彭博杰出教授,他很高兴地看到:

\n
\n

"The keynotes really highlighted how Galaxy enables cutting edge science.”
\n“主题演讲真正强调了 Galaxy 如何实现尖端科学。”

\n
\n

来自 BioCommons、昆士兰网络基础设施基金会 (QCIF)、昆士兰大学、墨尔本生物信息学和 AARNet 的 Galaxy Australia 团队成员发表了从监测工具健康状况到开发最近发布的 Galaxy Australia 基因组实验室等主题。澳大利亚银河服务项目负责人 Gareth Price 博士表示:

\n
\n

“There was a fantastic exchange between our team and international colleagues and wonderful opportunities to engage with the global Galaxy community. GCC was an exhilarating experience, and it was inspiring to be surrounded by like-minded people. The team left full of energy to keep improving Galaxy Australia and strengthen their collaborations with the wider Galaxy community.”
\n“我们的团队与国际同事之间进行了精彩的交流,并有绝佳的机会与全球 Galaxy 社区互动。 GCC 是一次令人兴奋的经历,周围都是志趣相投的人,这很鼓舞人心。该团队充满活力地继续改进 Galaxy Australia,并加强与更广泛的 Galaxy 社区的合作。”

\n
\n

虽然我们是在昆士兰科技大学 (QUT) 的 The Cube 一流设施中举办的,但远程参与的能力是举办真正国际会议的关键因素。尽管 Amrita 大学系统基因组学首席科学家 Prash Suravajhala 博士是 GCC2023 组委会成员,但他无法从印度出发,但他:

\n
\n

“Very excited and happy to be a part of GCC2023 virtually. We witnessed scintillating talks and brainstorming sessions, and the virtual attendance was a treat. This was a cherishing moment for me as I guzzled the talks from early morning India time! It has created a great camaraderie."
\n“能够以虚拟方式参加 GCC2023 感到非常兴奋和高兴。我们目睹了精彩的演讲和头脑风暴会议,虚拟出席是一种享受。这对我来说是一个珍贵的时刻,因为我沉迷于印度时间清晨的演讲!它创造了伟大的友情。"

\n
\n

Recognition

\n

特别感谢 GCC2023 的赞助商:

\n

白金赞助商

\n

BizData (https://www.bizdata.com.au/)

\n

银牌赞助商

\n

Limagrain (https://www.limagrain.com/en)

\n

GalaxyWorks (https://galaxyworks.io/)

\n

铜牌赞助商

\n

GIGA Science (https://academic.oup.com/gigascience?login=false)

\n

非常感谢所有使 GCC2023 取得成功的个人:

\n

组织和科学委员会

\n

Andrew Lonie

\n

Christina Hall

\n

Enis Afgan

\n

Gareth Price

\n

Jenn Vessio

\n

Margita Jadan

\n

Prash Suravajhala

\n

Roberto Barrero Gumiel

\n

Ross Lazarus

\n

Assunta DeSanto

\n

Natalie Whitaker

\n

Simon Gladman

\n

Claudia Melogno de Sandoval

\n

培训协调员

\n

Assunta DeSanto

\n

Igor Makunin

\n

Mark Crowe

\n

在线支持

\n

Melissa Burke

\n

Patrick Capon

\n

科学计划成员

\n

Andrew Lonie

\n

Anne Claire Fouilloux

\n

Anna Syme

\n

Anshu Bhardwaj

\n

Bérénice Batut

\n

Bryan Raubenolt

\n

Cameron Hyde

\n

Catherine Bromhead

\n

Clare Sloggett

\n

Cristóbal Gallardo

\n

Dan Blankenberg

\n

Davor Davidović

\n

Enis Afgan

\n

Frederik Coppens

\n

Hans-Rudolf Hotz

\n

Ivan Jakovlić

\n

Jeremy Goecks

\n

Justin Lee

\n

Margita Jadan

\n

Maria Doyle

\n

Matthias Bernt

\n

Natalie Kucher

\n

Nicola Soranzo

\n

Nuwan Goonasekera

\n

Peter van Heusden

\n

Ralf Weber

\n

Ross Lazarus

\n

Soyean Kim

\n

Thomas Harrop

\n

Timothy Griffin

\n

Tyler Collins

\n

Wendi Bacon

\n

Yvan Le Bras

\n

联合节主办方

\n

Cameron Hyde

\n

附录一

\n

GCC2023 Meeting Report Image10

\n

GCC2023 Meeting Report Image11

\n

GCC2023 Meeting Report Image12

\n

GCC2023 Meeting Report Image13

\n

GCC2023 Meeting Report Image14

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.3-资讯'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '兆碱基中关于 Kb、KB、Bps、bps 的区别', 'number': 20, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/20', 'createdAt': '2023-11-23T01:39:14Z', 'lastEditedAt': '2023-11-23T02:48:23Z', 'updatedAt': '2023-11-23T02:48:23Z', 'body': '生物信息很多文章都提到 DNA 序列的 100 万个碱基数据(兆碱基)大致相当于计算机 1 兆的存储空间。借着这个问题,我们今天来聊一聊计算机存储和数据传输中 Kb、KB、Bps、bps 的一些区别,分析一下所谓的兆碱基到底是使用哪一种标准(单位)怎么计算出来的。\r\n\r\n\r\n\r\n## 计算机存储容量单位\r\n\r\nBit (binary digit):亦称二进制位,指二进制中的一位,是信息的最小单位。位的值只会是 0 或 1。虽然计算机也提供对位的判断和操作,但是计算机指令一般以字节(Byte)为单位。在大多数的计算机系统中,八位是一个字节。一位的值通常以存储电容是否带电来衡量。\r\n\r\nB (Byte):字节。8 个二进制位构成 1 个"字节(Byte)",它是电脑存储空间的基本计量单位。1 字节 (Byte)=8(bit) 位,就是有 8 个二进制数组成。1 个英文字符是 1 个字节,也就是 1B;1 个汉字为 2 个字符,也就是 2B。\r\n\r\nGB (Gigabyte):吉字节,是一种**十进制**的信息计量单位。Gibibyte(giga binary byte 的缩写)则是**二进制**信息计量的一个单位,简称 GiB。吉字节(Gigabyte)常容易和二进制的信息计量单位 Gibibyte 混淆。\r\n\r\n> Gibibyte 与 Gigabyte 常常被混淆,前者的计算方式是二进制,后者的计算方式是十进制。现今的计算上,常把 Gigabyte 以二进制的方式计算,即 $2^{30} = 1,073,741,824$ 。(因为 Windows 对 GB 这个信息计量单位的误用,因此在 Windows 中显示的 "1GB",其实应是指 "1GiB",但 Windows 却显示为 "1GB",而常造成误解。误用会普遍化的一大因素,是因为 Windows 的操作系统占有率高),由于两种换算方法的不同,使容量在计算上相差了 7.3%,所以常有 Windows 系统报告的容量比硬盘标示的容量还要小的情况发生。但在苹果公司的 OS X 操作系统中,对于存储设备的容量计算方式与硬盘厂商一致,均为 1GB = 1,000,000,000 ( $10^{9}$ ) 字节的十进制,避免了计算和使用上的麻烦。\r\n>\r\n> —— 维基百科 - Gibibyte,\r\n\r\nK、M、G 都是 KB、MB、GB 的简称。由于混淆已经普遍化,Gigabyte 往往是指 Gibibyte,所以平时我们说的 1 兆存储就是 1M(MB),1G 存储就是 1GB)。我们的照片一般是 104KB、209KB、1.45MB、2.45MB、3.32MB 等等。\r\n\r\n在说明其他储存单位的换算前,我们来看看两个标准:SI、IEC。\r\n\r\n### 国际单位制(SI)\r\n\r\n国际单位制(简称 SI,来自于法语 Système International d\'Unités),是世界上最普遍采用的标准度量系统。国际单位制以七个基本单位(米(m),千克(kg),秒(s),安培(A),开尔文(K),摩尔(mol),坎德拉(cd))为基础,由此建立起一系列相互换算关系明确的"一致单位"。另有二十个基于十进制的词头,当加在单位名称或符号前的时候,可用于表达该单位的倍数或分数。\r\n\r\n### 国际电工委员会(IEC)\r\n\r\n国际电工委员会(IEC, International Electrotechnical Commission)成立于 1906 年,至今已有 90 多年的历史。它是世界上成立最早的国际性电工标准化机构,负责有关电气工程和电子工程领域中的国际标准化工作。\r\n\r\nIEC 的宗旨是,促进电气、电子工程领域中标准化及有关问题的国际合作,增进国际间的相互了解。为实现这一目的,IEC 出版包括国际标准在内的各种出版物,并希望各成员在本国条件允许的情况下,在本国的标准化工作中使用这些标准。\r\n\r\n目前 IEC 的工作领域已由单纯研究电气设备、电机的名词术语和功率等问题扩展到电子、电力、微电子及其应用、通讯、视听、机器人、信息技术、新型医疗器械和核仪表等电工技术的各个方面。IEC 标准的权威性是世界公认的,截止到 2008 年 12 月底,IEC 已制定了 5425 个国际标准。\r\n\r\n不同标准下储存单位的次方单位 ( $2^{10}=1024$ ):\r\n\r\n![字节的次方单位](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/byte-wiki.png)\r\n\r\n## 比特率单位\r\n\r\n在电信和计算领域,比特率(Bit rate)是指单位时间内传输送或处理的比特的数量。比特率经常在电信领域用作连接速度、传输速度、信息传输速率和数字带宽容量的同义词。\r\n\r\n在数字多媒体领域,比特率是单位时间播放连续的媒体如压缩后的音频或视频的比特数量。在这个意义上讲,它相当于术语数字带宽消耗量,或吞吐量。\r\n\r\n比特率规定使用"比特每秒"(bit/s 或 bps)为单位,经常和国际单位制词头关联在一起:\r\n\r\n- bps(bit/s),即 bit pro second(位每秒);\r\n\r\n- Kbps(Kbit/s),即 Kilobit pro second(千位每秒);\r\n\r\n- Mbps(Mbit/s),即 Milionbit pro second(百万位每秒)。\r\n\r\n其中,bit 即比特,通常用 b(小写)表示,指一位二进制位,Milionbit=1000Kilobit=1000 000bit,所以 1Mbps=1000 000bps;\r\n\r\n### bps 和 Bps\r\n\r\nbps 是通常用来**衡量带宽**的单位,常见于表示数据机及网络通讯的传输速率,指每秒钟传输的二进制位数。例如 GigabitEthernet 端口。\r\n```\r\n5 minute input rate 38410000 bits/sec, 6344 packets/sec\r\n382410000 bits/sec = 382.41Mbps\r\n```\r\n\r\n通常电脑(软件)上显示的上传下载速度(如下面的阿里云 OSSBrowser、Google Chrome 数据下载速度),则是指每秒种传输的字节数(Byte)通常用 B(大写)表示:MB 即百万字节也称兆字节;KB 即千字节;B 即字节。\r\n\r\n- 1B=8b\r\n\r\n- 1MB=1024KB=1024\\*1024B\r\n\r\n- 1Mbps=1000Kbps=1000/8KBps=125KBps\r\n\r\n我们通常说的 1M 带宽即指 1Mbps,因此 1M 的带宽下载的速度一般不会超过 125KB 每秒。2M、3M 带宽的下载速度分别不会超过 250KB、375KB 每秒。\r\n\r\n![download-byte-rate](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/download-byte-rate.png)\r\n\r\n**数据传输速率的衡量单位 K 是十进制含义,但数据存储的 K 是 2 进制含义。**\r\n\r\n1kbit/s 就是 1000bit/s,而 KB 是 1024 个字节,注意 KB(KByte) 和 kbit 的区别,另外,数据传输速率的单位是 bit/s 记作:bps 。\r\n\r\n在实际应用中:\r\n\r\n- 1kbps=1000bps\r\n\r\n- 1Mbps=1000,000bps\r\n\r\n- 1bps=0.000001bps\r\n\r\n1Mbps 与 1m/s 是有区别的,1m/s 指的是 1024KB/s,而 1Mbps 指的是(1000/8)KB/s 也就是 125KB/S。\r\n\r\n记住 K 和 k 是没区别的 \xa0,区别在于 bps 属于位每秒的单位,而 m/s ,KB/s 这两个属于字节每秒的单位,一字节等于 8 位,即 1k=8b。\r\n\r\n## 兆碱基\r\n\r\n所以,在文章开头提到的 DNA 序列的 100 万个碱基数据(兆碱基)大致相当于计算机 1 兆的存储空间。其实也就是这么计算来得:\r\n\r\n一个碱基就是一个英文字母,而一个英文字母是 1 个字节(Byte),所以 100 万个碱基就是 1000,000 Byte。按照 SI 国际单位的十进制标准,正好相当于 1 MB,如果按照 IEC 国际电工委员会的二进制标准,应该为:1000,000 / 1024 /1024 ≈ 0.95 MB,则是大致相当于计算机 1 兆的存储空间。\r\n\r\n## 参考资料\r\n\r\n- [Wiki: Gibibyte](https://zh.wikipedia.org/wiki/Gibibyte),维基百科\r\n- [Wiki:比特率](https://zh.wikipedia.org/wiki/%E6%AF%94%E7%89%B9%E7%8E%87),维基百科\r\n- 沙翁,《[什么是 Mbps、Kbps、bps、kb、mb 及其换算和区别](https://www.cnblogs.com/shaweng/p/3816985.html)》,博客园\r\n- 大任 Dren,《[bit、Byte、bps、Bps、pps、Gbps 的单位详细说明及换算](https://blog.csdn.net/a9254778/article/details/8513086)》,CSDN-专业 IT 技术社区\r\n', 'bodyText': '生物信息很多文章都提到 DNA 序列的 100 万个碱基数据(兆碱基)大致相当于计算机 1 兆的存储空间。借着这个问题,我们今天来聊一聊计算机存储和数据传输中 Kb、KB、Bps、bps 的一些区别,分析一下所谓的兆碱基到底是使用哪一种标准(单位)怎么计算出来的。\n\n计算机存储容量单位\nBit (binary digit):亦称二进制位,指二进制中的一位,是信息的最小单位。位的值只会是 0 或 1。虽然计算机也提供对位的判断和操作,但是计算机指令一般以字节(Byte)为单位。在大多数的计算机系统中,八位是一个字节。一位的值通常以存储电容是否带电来衡量。\nB (Byte):字节。8 个二进制位构成 1 个"字节(Byte)",它是电脑存储空间的基本计量单位。1 字节 (Byte)=8(bit) 位,就是有 8 个二进制数组成。1 个英文字符是 1 个字节,也就是 1B;1 个汉字为 2 个字符,也就是 2B。\nGB (Gigabyte):吉字节,是一种十进制的信息计量单位。Gibibyte(giga binary byte 的缩写)则是二进制信息计量的一个单位,简称 GiB。吉字节(Gigabyte)常容易和二进制的信息计量单位 Gibibyte 混淆。\n\nGibibyte 与 Gigabyte 常常被混淆,前者的计算方式是二进制,后者的计算方式是十进制。现今的计算上,常把 Gigabyte 以二进制的方式计算,即 $2^{30} = 1,073,741,824$ 。(因为 Windows 对 GB 这个信息计量单位的误用,因此在 Windows 中显示的 "1GB",其实应是指 "1GiB",但 Windows 却显示为 "1GB",而常造成误解。误用会普遍化的一大因素,是因为 Windows 的操作系统占有率高),由于两种换算方法的不同,使容量在计算上相差了 7.3%,所以常有 Windows 系统报告的容量比硬盘标示的容量还要小的情况发生。但在苹果公司的 OS X 操作系统中,对于存储设备的容量计算方式与硬盘厂商一致,均为 1GB = 1,000,000,000 ( $10^{9}$ ) 字节的十进制,避免了计算和使用上的麻烦。\n—— 维基百科 - Gibibyte,https://zh.wikipedia.org/wiki/Gibibyte\n\nK、M、G 都是 KB、MB、GB 的简称。由于混淆已经普遍化,Gigabyte 往往是指 Gibibyte,所以平时我们说的 1 兆存储就是 1M(MB),1G 存储就是 1GB)。我们的照片一般是 104KB、209KB、1.45MB、2.45MB、3.32MB 等等。\n在说明其他储存单位的换算前,我们来看看两个标准:SI、IEC。\n国际单位制(SI)\n国际单位制(简称 SI,来自于法语 Système International d\'Unités),是世界上最普遍采用的标准度量系统。国际单位制以七个基本单位(米(m),千克(kg),秒(s),安培(A),开尔文(K),摩尔(mol),坎德拉(cd))为基础,由此建立起一系列相互换算关系明确的"一致单位"。另有二十个基于十进制的词头,当加在单位名称或符号前的时候,可用于表达该单位的倍数或分数。\n国际电工委员会(IEC)\n国际电工委员会(IEC, International Electrotechnical Commission)成立于 1906 年,至今已有 90 多年的历史。它是世界上成立最早的国际性电工标准化机构,负责有关电气工程和电子工程领域中的国际标准化工作。\nIEC 的宗旨是,促进电气、电子工程领域中标准化及有关问题的国际合作,增进国际间的相互了解。为实现这一目的,IEC 出版包括国际标准在内的各种出版物,并希望各成员在本国条件允许的情况下,在本国的标准化工作中使用这些标准。\n目前 IEC 的工作领域已由单纯研究电气设备、电机的名词术语和功率等问题扩展到电子、电力、微电子及其应用、通讯、视听、机器人、信息技术、新型医疗器械和核仪表等电工技术的各个方面。IEC 标准的权威性是世界公认的,截止到 2008 年 12 月底,IEC 已制定了 5425 个国际标准。\n不同标准下储存单位的次方单位 ( $2^{10}=1024$ ):\n\n比特率单位\n在电信和计算领域,比特率(Bit rate)是指单位时间内传输送或处理的比特的数量。比特率经常在电信领域用作连接速度、传输速度、信息传输速率和数字带宽容量的同义词。\n在数字多媒体领域,比特率是单位时间播放连续的媒体如压缩后的音频或视频的比特数量。在这个意义上讲,它相当于术语数字带宽消耗量,或吞吐量。\n比特率规定使用"比特每秒"(bit/s 或 bps)为单位,经常和国际单位制词头关联在一起:\n\n\nbps(bit/s),即 bit pro second(位每秒);\n\n\nKbps(Kbit/s),即 Kilobit pro second(千位每秒);\n\n\nMbps(Mbit/s),即 Milionbit pro second(百万位每秒)。\n\n\n其中,bit 即比特,通常用 b(小写)表示,指一位二进制位,Milionbit=1000Kilobit=1000 000bit,所以 1Mbps=1000 000bps;\nbps 和 Bps\nbps 是通常用来衡量带宽的单位,常见于表示数据机及网络通讯的传输速率,指每秒钟传输的二进制位数。例如 GigabitEthernet 端口。\n5 minute input rate 38410000 bits/sec, 6344 packets/sec\n382410000 bits/sec = 382.41Mbps\n\n通常电脑(软件)上显示的上传下载速度(如下面的阿里云 OSSBrowser、Google Chrome 数据下载速度),则是指每秒种传输的字节数(Byte)通常用 B(大写)表示:MB 即百万字节也称兆字节;KB 即千字节;B 即字节。\n\n\n1B=8b\n\n\n1MB=1024KB=1024*1024B\n\n\n1Mbps=1000Kbps=1000/8KBps=125KBps\n\n\n我们通常说的 1M 带宽即指 1Mbps,因此 1M 的带宽下载的速度一般不会超过 125KB 每秒。2M、3M 带宽的下载速度分别不会超过 250KB、375KB 每秒。\n\n数据传输速率的衡量单位 K 是十进制含义,但数据存储的 K 是 2 进制含义。\n1kbit/s 就是 1000bit/s,而 KB 是 1024 个字节,注意 KB(KByte) 和 kbit 的区别,另外,数据传输速率的单位是 bit/s 记作:bps 。\n在实际应用中:\n\n\n1kbps=1000bps\n\n\n1Mbps=1000,000bps\n\n\n1bps=0.000001bps\n\n\n1Mbps 与 1m/s 是有区别的,1m/s 指的是 1024KB/s,而 1Mbps 指的是(1000/8)KB/s 也就是 125KB/S。\n记住 K 和 k 是没区别的 \xa0,区别在于 bps 属于位每秒的单位,而 m/s ,KB/s 这两个属于字节每秒的单位,一字节等于 8 位,即 1k=8b。\n兆碱基\n所以,在文章开头提到的 DNA 序列的 100 万个碱基数据(兆碱基)大致相当于计算机 1 兆的存储空间。其实也就是这么计算来得:\n一个碱基就是一个英文字母,而一个英文字母是 1 个字节(Byte),所以 100 万个碱基就是 1000,000 Byte。按照 SI 国际单位的十进制标准,正好相当于 1 MB,如果按照 IEC 国际电工委员会的二进制标准,应该为:1000,000 / 1024 /1024 ≈ 0.95 MB,则是大致相当于计算机 1 兆的存储空间。\n参考资料\n\nWiki: Gibibyte,维基百科\nWiki:比特率,维基百科\n沙翁,《什么是 Mbps、Kbps、bps、kb、mb 及其换算和区别》,博客园\n大任 Dren,《bit、Byte、bps、Bps、pps、Gbps 的单位详细说明及换算》,CSDN-专业 IT 技术社区', 'bodyHTML': '

生物信息很多文章都提到 DNA 序列的 100 万个碱基数据(兆碱基)大致相当于计算机 1 兆的存储空间。借着这个问题,我们今天来聊一聊计算机存储和数据传输中 Kb、KB、Bps、bps 的一些区别,分析一下所谓的兆碱基到底是使用哪一种标准(单位)怎么计算出来的。

\n\n

计算机存储容量单位

\n

Bit (binary digit):亦称二进制位,指二进制中的一位,是信息的最小单位。位的值只会是 0 或 1。虽然计算机也提供对位的判断和操作,但是计算机指令一般以字节(Byte)为单位。在大多数的计算机系统中,八位是一个字节。一位的值通常以存储电容是否带电来衡量。

\n

B (Byte):字节。8 个二进制位构成 1 个"字节(Byte)",它是电脑存储空间的基本计量单位。1 字节 (Byte)=8(bit) 位,就是有 8 个二进制数组成。1 个英文字符是 1 个字节,也就是 1B;1 个汉字为 2 个字符,也就是 2B。

\n

GB (Gigabyte):吉字节,是一种十进制的信息计量单位。Gibibyte(giga binary byte 的缩写)则是二进制信息计量的一个单位,简称 GiB。吉字节(Gigabyte)常容易和二进制的信息计量单位 Gibibyte 混淆。

\n
\n

Gibibyte 与 Gigabyte 常常被混淆,前者的计算方式是二进制,后者的计算方式是十进制。现今的计算上,常把 Gigabyte 以二进制的方式计算,即 $2^{30} = 1,073,741,824$ 。(因为 Windows 对 GB 这个信息计量单位的误用,因此在 Windows 中显示的 "1GB",其实应是指 "1GiB",但 Windows 却显示为 "1GB",而常造成误解。误用会普遍化的一大因素,是因为 Windows 的操作系统占有率高),由于两种换算方法的不同,使容量在计算上相差了 7.3%,所以常有 Windows 系统报告的容量比硬盘标示的容量还要小的情况发生。但在苹果公司的 OS X 操作系统中,对于存储设备的容量计算方式与硬盘厂商一致,均为 1GB = 1,000,000,000 ( $10^{9}$ ) 字节的十进制,避免了计算和使用上的麻烦。

\n

—— 维基百科 - Gibibyte,https://zh.wikipedia.org/wiki/Gibibyte

\n
\n

K、M、G 都是 KB、MB、GB 的简称。由于混淆已经普遍化,Gigabyte 往往是指 Gibibyte,所以平时我们说的 1 兆存储就是 1M(MB),1G 存储就是 1GB)。我们的照片一般是 104KB、209KB、1.45MB、2.45MB、3.32MB 等等。

\n

在说明其他储存单位的换算前,我们来看看两个标准:SI、IEC。

\n

国际单位制(SI)

\n

国际单位制(简称 SI,来自于法语 Système International d\'Unités),是世界上最普遍采用的标准度量系统。国际单位制以七个基本单位(米(m),千克(kg),秒(s),安培(A),开尔文(K),摩尔(mol),坎德拉(cd))为基础,由此建立起一系列相互换算关系明确的"一致单位"。另有二十个基于十进制的词头,当加在单位名称或符号前的时候,可用于表达该单位的倍数或分数。

\n

国际电工委员会(IEC)

\n

国际电工委员会(IEC, International Electrotechnical Commission)成立于 1906 年,至今已有 90 多年的历史。它是世界上成立最早的国际性电工标准化机构,负责有关电气工程和电子工程领域中的国际标准化工作。

\n

IEC 的宗旨是,促进电气、电子工程领域中标准化及有关问题的国际合作,增进国际间的相互了解。为实现这一目的,IEC 出版包括国际标准在内的各种出版物,并希望各成员在本国条件允许的情况下,在本国的标准化工作中使用这些标准。

\n

目前 IEC 的工作领域已由单纯研究电气设备、电机的名词术语和功率等问题扩展到电子、电力、微电子及其应用、通讯、视听、机器人、信息技术、新型医疗器械和核仪表等电工技术的各个方面。IEC 标准的权威性是世界公认的,截止到 2008 年 12 月底,IEC 已制定了 5425 个国际标准。

\n

不同标准下储存单位的次方单位 ( $2^{10}=1024$ ):

\n

字节的次方单位

\n

比特率单位

\n

在电信和计算领域,比特率(Bit rate)是指单位时间内传输送或处理的比特的数量。比特率经常在电信领域用作连接速度、传输速度、信息传输速率和数字带宽容量的同义词。

\n

在数字多媒体领域,比特率是单位时间播放连续的媒体如压缩后的音频或视频的比特数量。在这个意义上讲,它相当于术语数字带宽消耗量,或吞吐量。

\n

比特率规定使用"比特每秒"(bit/s 或 bps)为单位,经常和国际单位制词头关联在一起:

\n
    \n
  • \n

    bps(bit/s),即 bit pro second(位每秒);

    \n
  • \n
  • \n

    Kbps(Kbit/s),即 Kilobit pro second(千位每秒);

    \n
  • \n
  • \n

    Mbps(Mbit/s),即 Milionbit pro second(百万位每秒)。

    \n
  • \n
\n

其中,bit 即比特,通常用 b(小写)表示,指一位二进制位,Milionbit=1000Kilobit=1000 000bit,所以 1Mbps=1000 000bps;

\n

bps 和 Bps

\n

bps 是通常用来衡量带宽的单位,常见于表示数据机及网络通讯的传输速率,指每秒钟传输的二进制位数。例如 GigabitEthernet 端口。

\n
5 minute input rate 38410000 bits/sec, 6344 packets/sec\n382410000 bits/sec = 382.41Mbps\n
\n

通常电脑(软件)上显示的上传下载速度(如下面的阿里云 OSSBrowser、Google Chrome 数据下载速度),则是指每秒种传输的字节数(Byte)通常用 B(大写)表示:MB 即百万字节也称兆字节;KB 即千字节;B 即字节。

\n
    \n
  • \n

    1B=8b

    \n
  • \n
  • \n

    1MB=1024KB=1024*1024B

    \n
  • \n
  • \n

    1Mbps=1000Kbps=1000/8KBps=125KBps

    \n
  • \n
\n

我们通常说的 1M 带宽即指 1Mbps,因此 1M 的带宽下载的速度一般不会超过 125KB 每秒。2M、3M 带宽的下载速度分别不会超过 250KB、375KB 每秒。

\n

download-byte-rate

\n

数据传输速率的衡量单位 K 是十进制含义,但数据存储的 K 是 2 进制含义。

\n

1kbit/s 就是 1000bit/s,而 KB 是 1024 个字节,注意 KB(KByte) 和 kbit 的区别,另外,数据传输速率的单位是 bit/s 记作:bps 。

\n

在实际应用中:

\n
    \n
  • \n

    1kbps=1000bps

    \n
  • \n
  • \n

    1Mbps=1000,000bps

    \n
  • \n
  • \n

    1bps=0.000001bps

    \n
  • \n
\n

1Mbps 与 1m/s 是有区别的,1m/s 指的是 1024KB/s,而 1Mbps 指的是(1000/8)KB/s 也就是 125KB/S。

\n

记住 K 和 k 是没区别的 \xa0,区别在于 bps 属于位每秒的单位,而 m/s ,KB/s 这两个属于字节每秒的单位,一字节等于 8 位,即 1k=8b。

\n

兆碱基

\n

所以,在文章开头提到的 DNA 序列的 100 万个碱基数据(兆碱基)大致相当于计算机 1 兆的存储空间。其实也就是这么计算来得:

\n

一个碱基就是一个英文字母,而一个英文字母是 1 个字节(Byte),所以 100 万个碱基就是 1000,000 Byte。按照 SI 国际单位的十进制标准,正好相当于 1 MB,如果按照 IEC 国际电工委员会的二进制标准,应该为:1000,000 / 1024 /1024 ≈ 0.95 MB,则是大致相当于计算机 1 兆的存储空间。

\n

参考资料

\n', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.4-知识'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '沉浸式双语网页翻译扩展', 'number': 19, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/19', 'createdAt': '2023-11-23T01:07:46Z', 'lastEditedAt': '2024-04-19T08:57:37Z', 'updatedAt': '2024-04-19T08:57:37Z', 'body': '向大家极力推荐这个插件:**沉浸式双语网页翻译扩展**,浏览器翻译神器,而且**完全免费**!\r\n\r\n- **GitHub:** [https://github.com/immersive-translate/immersive-translate](https://github.com/immersive-translate/immersive-translate)\r\n- 如果你是 **Mac** 系统,推荐:[https://github.com/ripperhe/Bob](https://github.com/ripperhe/Bob)\r\n\r\n\r\n\r\n![image.png](https://shub.weiyan.tech/yuque/elog-cookbook-img/FtAZvqEDdgc3yfpbqwRq40MUEfld.png)\r\n\r\n**截图**\r\n![Twitter 翻译](https://shub.weiyan.tech/yuque/elog-cookbook-img/FpC4e5Sf_G5YT9bzCWSTl4oBIBVO.png "Twitter 翻译")\r\n\r\n![pdf 文件翻译](https://shub.weiyan.tech/yuque/elog-cookbook-img/FpImmIXzUhUNXaD-OgDI1AArm2eu.png "pdf 文件翻译")\r\n\r\n![Reddit 高亮译文样式](https://shub.weiyan.tech/yuque/elog-cookbook-img/FuFqmDqRNOZl_es2sVoRkmeMDAar.png "Reddit 高亮译文样式")\r\n', 'bodyText': '向大家极力推荐这个插件:沉浸式双语网页翻译扩展,浏览器翻译神器,而且完全免费!\n\nGitHub: https://github.com/immersive-translate/immersive-translate\n如果你是 Mac 系统,推荐:https://github.com/ripperhe/Bob\n\n\n\n截图', 'bodyHTML': '

向大家极力推荐这个插件:沉浸式双语网页翻译扩展,浏览器翻译神器,而且完全免费

\n\n\n

image.png

\n

截图
\nTwitter 翻译

\n

pdf 文件翻译

\n

Reddit 高亮译文样式

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '跨端博客解决方案 Elog 使用', 'number': 18, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/18', 'createdAt': '2023-11-23T01:04:15Z', 'lastEditedAt': None, 'updatedAt': '2024-01-04T05:44:58Z', 'body': 'Elog () —— 开放式跨平台博客解决方案,随意组合写作平台 (语雀/Notion/FlowUs) 和部署平台 (Hexo/Vitepress 等 。\r\n\r\n\r\n\r\n主要配置文件 **elog.config.js**:\r\n\r\n```javascript\r\nmodule.exports = {\r\n write: {\r\n platform: "yuque",\r\n yuque: {\r\n token: process.env.YUQUE_TOKEN,\r\n baseUrl: "",\r\n login: process.env.YUQUE_LOGIN,\r\n repo: process.env.YUQUE_REPO,\r\n onlyPublic: false,\r\n onlyPublished: true,\r\n },\r\n notion: {\r\n token: process.env.NOTION_TOKEN,\r\n databaseId: process.env.NOTION_DATABASE_ID,\r\n filter: true, // {property: \'status\', select: {equals: \'已发布\'}}\r\n sorts: true, // [{timestamp: \'created_time\', direction: \'descending\'}],\r\n catalog: false,\r\n },\r\n flowus: {\r\n tablePageId: process.env.FLOWUS_TABLE_PAGE_ID,\r\n filter: true, // {property: \'status\',value: \'已发布\'}\r\n sort: true, // { property: \'createdAt\', direction: \'descending\' }\r\n catalog: false,\r\n },\r\n },\r\n deploy: {\r\n platform: "local",\r\n local: {\r\n outputDir: "./Cookbook",\r\n filename: "title", //生成文档的命名格式,取值 urlname|title\r\n format: "markdown",\r\n catalog: true, //是否按照目录生成文档\r\n formatExt: "",\r\n },\r\n confluence: {\r\n user: process.env.CONFLUENCE_USER,\r\n password: process.env.CONFLUENCE_PASSWORD,\r\n baseUrl: process.env.CONFLUENCE_BASE_URL,\r\n spaceKey: process.env.CONFLUENCE_SPACE_KEY,\r\n rootPageId: process.env.CONFLUENCE_ROOT_PAGE_ID, // 可选\r\n formatExt: "", // 可选\r\n },\r\n },\r\n image: {\r\n enable: true,\r\n platform: "local",\r\n local: {\r\n outputDir: "./Images", //本地图片保存目录\r\n prefixKey: "/cookbook", //替换图片的url前缀,如 ![image.png](/cookbook/xxxx.png)\r\n },\r\n oss: {\r\n secretId: process.env.OSS_SECRET_ID,\r\n secretKey: process.env.OSS_SECRET_KEY,\r\n bucket: process.env.OSS_BUCKET,\r\n region: process.env.OSS_REGION,\r\n host: process.env.OSS_HOST,\r\n prefixKey: "",\r\n secretExt: "", // 可选\r\n },\r\n cos: {\r\n secretId: process.env.COS_SECRET_ID,\r\n secretKey: process.env.COS_SECRET_KEY,\r\n bucket: process.env.COS_BUCKET,\r\n region: process.env.COS_REGION,\r\n host: process.env.COS_HOST,\r\n prefixKey: "",\r\n secretExt: "", // 可选\r\n },\r\n qiniu: {\r\n secretId: process.env.QINIU_SECRET_ID,\r\n secretKey: process.env.QINIU_SECRET_KEY,\r\n bucket: process.env.QINIU_BUCKET,\r\n region: process.env.QINIU_REGION,\r\n host: process.env.QINIU_HOST,\r\n prefixKey: "",\r\n secretExt: "", // 可选\r\n },\r\n upyun: {\r\n user: process.env.UPYUN_USER,\r\n password: process.env.UPYUN_PASSWORD,\r\n bucket: process.env.UPYUN_BUCKET,\r\n host: process.env.UPYUN_HOST,\r\n prefixKey: "",\r\n secretExt: "", // 可选\r\n },\r\n github: {\r\n user: process.env.GITHUB_USER,\r\n token: process.env.GITHUB_TOKEN,\r\n repo: process.env.GITHUB_REPO,\r\n branch: "",\r\n host: "",\r\n prefixKey: "",\r\n secretExt: "", // 可选\r\n },\r\n },\r\n};\r\n```\r\n\r\n基于语雀 WebHook 实现实时同步:\r\n', 'bodyText': 'Elog (https://github.com/LetTTGACO/elog) —— 开放式跨平台博客解决方案,随意组合写作平台 (语雀/Notion/FlowUs) 和部署平台 (Hexo/Vitepress 等 。\n\n主要配置文件 elog.config.js:\nmodule.exports = {\n write: {\n platform: "yuque",\n yuque: {\n token: process.env.YUQUE_TOKEN,\n baseUrl: "",\n login: process.env.YUQUE_LOGIN,\n repo: process.env.YUQUE_REPO,\n onlyPublic: false,\n onlyPublished: true,\n },\n notion: {\n token: process.env.NOTION_TOKEN,\n databaseId: process.env.NOTION_DATABASE_ID,\n filter: true, // {property: \'status\', select: {equals: \'已发布\'}}\n sorts: true, // [{timestamp: \'created_time\', direction: \'descending\'}],\n catalog: false,\n },\n flowus: {\n tablePageId: process.env.FLOWUS_TABLE_PAGE_ID,\n filter: true, // {property: \'status\',value: \'已发布\'}\n sort: true, // { property: \'createdAt\', direction: \'descending\' }\n catalog: false,\n },\n },\n deploy: {\n platform: "local",\n local: {\n outputDir: "./Cookbook",\n filename: "title", //生成文档的命名格式,取值 urlname|title\n format: "markdown",\n catalog: true, //是否按照目录生成文档\n formatExt: "",\n },\n confluence: {\n user: process.env.CONFLUENCE_USER,\n password: process.env.CONFLUENCE_PASSWORD,\n baseUrl: process.env.CONFLUENCE_BASE_URL,\n spaceKey: process.env.CONFLUENCE_SPACE_KEY,\n rootPageId: process.env.CONFLUENCE_ROOT_PAGE_ID, // 可选\n formatExt: "", // 可选\n },\n },\n image: {\n enable: true,\n platform: "local",\n local: {\n outputDir: "./Images", //本地图片保存目录\n prefixKey: "/cookbook", //替换图片的url前缀,如 ![image.png](/cookbook/xxxx.png)\n },\n oss: {\n secretId: process.env.OSS_SECRET_ID,\n secretKey: process.env.OSS_SECRET_KEY,\n bucket: process.env.OSS_BUCKET,\n region: process.env.OSS_REGION,\n host: process.env.OSS_HOST,\n prefixKey: "",\n secretExt: "", // 可选\n },\n cos: {\n secretId: process.env.COS_SECRET_ID,\n secretKey: process.env.COS_SECRET_KEY,\n bucket: process.env.COS_BUCKET,\n region: process.env.COS_REGION,\n host: process.env.COS_HOST,\n prefixKey: "",\n secretExt: "", // 可选\n },\n qiniu: {\n secretId: process.env.QINIU_SECRET_ID,\n secretKey: process.env.QINIU_SECRET_KEY,\n bucket: process.env.QINIU_BUCKET,\n region: process.env.QINIU_REGION,\n host: process.env.QINIU_HOST,\n prefixKey: "",\n secretExt: "", // 可选\n },\n upyun: {\n user: process.env.UPYUN_USER,\n password: process.env.UPYUN_PASSWORD,\n bucket: process.env.UPYUN_BUCKET,\n host: process.env.UPYUN_HOST,\n prefixKey: "",\n secretExt: "", // 可选\n },\n github: {\n user: process.env.GITHUB_USER,\n token: process.env.GITHUB_TOKEN,\n repo: process.env.GITHUB_REPO,\n branch: "",\n host: "",\n prefixKey: "",\n secretExt: "", // 可选\n },\n },\n};\n基于语雀 WebHook 实现实时同步:https://github.com/LetTTGACO/serverless-api', 'bodyHTML': '

Elog (https://github.com/LetTTGACO/elog) —— 开放式跨平台博客解决方案,随意组合写作平台 (语雀/Notion/FlowUs) 和部署平台 (Hexo/Vitepress 等 。

\n\n

主要配置文件 elog.config.js

\n
module.exports = {\n  write: {\n    platform: "yuque",\n    yuque: {\n      token: process.env.YUQUE_TOKEN,\n      baseUrl: "",\n      login: process.env.YUQUE_LOGIN,\n      repo: process.env.YUQUE_REPO,\n      onlyPublic: false,\n      onlyPublished: true,\n    },\n    notion: {\n      token: process.env.NOTION_TOKEN,\n      databaseId: process.env.NOTION_DATABASE_ID,\n      filter: true, // {property: \'status\', select: {equals: \'已发布\'}}\n      sorts: true, // [{timestamp: \'created_time\', direction: \'descending\'}],\n      catalog: false,\n    },\n    flowus: {\n      tablePageId: process.env.FLOWUS_TABLE_PAGE_ID,\n      filter: true, // {property: \'status\',value: \'已发布\'}\n      sort: true, // { property: \'createdAt\', direction: \'descending\' }\n      catalog: false,\n    },\n  },\n  deploy: {\n    platform: "local",\n    local: {\n      outputDir: "./Cookbook",\n      filename: "title", //生成文档的命名格式,取值 urlname|title\n      format: "markdown",\n      catalog: true, //是否按照目录生成文档\n      formatExt: "",\n    },\n    confluence: {\n      user: process.env.CONFLUENCE_USER,\n      password: process.env.CONFLUENCE_PASSWORD,\n      baseUrl: process.env.CONFLUENCE_BASE_URL,\n      spaceKey: process.env.CONFLUENCE_SPACE_KEY,\n      rootPageId: process.env.CONFLUENCE_ROOT_PAGE_ID, // 可选\n      formatExt: "", // 可选\n    },\n  },\n  image: {\n    enable: true,\n    platform: "local",\n    local: {\n      outputDir: "./Images", //本地图片保存目录\n      prefixKey: "/cookbook", //替换图片的url前缀,如 ![image.png](/cookbook/xxxx.png)\n    },\n    oss: {\n      secretId: process.env.OSS_SECRET_ID,\n      secretKey: process.env.OSS_SECRET_KEY,\n      bucket: process.env.OSS_BUCKET,\n      region: process.env.OSS_REGION,\n      host: process.env.OSS_HOST,\n      prefixKey: "",\n      secretExt: "", // 可选\n    },\n    cos: {\n      secretId: process.env.COS_SECRET_ID,\n      secretKey: process.env.COS_SECRET_KEY,\n      bucket: process.env.COS_BUCKET,\n      region: process.env.COS_REGION,\n      host: process.env.COS_HOST,\n      prefixKey: "",\n      secretExt: "", // 可选\n    },\n    qiniu: {\n      secretId: process.env.QINIU_SECRET_ID,\n      secretKey: process.env.QINIU_SECRET_KEY,\n      bucket: process.env.QINIU_BUCKET,\n      region: process.env.QINIU_REGION,\n      host: process.env.QINIU_HOST,\n      prefixKey: "",\n      secretExt: "", // 可选\n    },\n    upyun: {\n      user: process.env.UPYUN_USER,\n      password: process.env.UPYUN_PASSWORD,\n      bucket: process.env.UPYUN_BUCKET,\n      host: process.env.UPYUN_HOST,\n      prefixKey: "",\n      secretExt: "", // 可选\n    },\n    github: {\n      user: process.env.GITHUB_USER,\n      token: process.env.GITHUB_TOKEN,\n      repo: process.env.GITHUB_REPO,\n      branch: "",\n      host: "",\n      prefixKey: "",\n      secretExt: "", // 可选\n    },\n  },\n};
\n

基于语雀 WebHook 实现实时同步:https://github.com/LetTTGACO/serverless-api

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'NCBI API 使用', 'number': 17, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/17', 'createdAt': '2023-11-21T06:44:23Z', 'lastEditedAt': None, 'updatedAt': '2023-11-21T06:44:24Z', 'body': '参考:https://www.ncbi.nlm.nih.gov/books/NBK25499/', 'bodyText': '参考:https://www.ncbi.nlm.nih.gov/books/NBK25499/', 'bodyHTML': '

参考:https://www.ncbi.nlm.nih.gov/books/NBK25499/

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.1-生信'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '留言与建议', 'number': 16, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/16', 'createdAt': '2023-11-09T07:42:48Z', 'lastEditedAt': '2024-10-23T06:29:59Z', 'updatedAt': '2024-10-23T06:30:45Z', 'body': '如果你通过本人的博文/平台学到了一点东西,那么对我最好的奖赏就是请你也尝试教我些东西。你可以通过邮箱、微信,或者移步到 “[GitHub Discussions](https://github.com/shenweiyan/Knowledge-Garden/discussions/16)” 写下您的建议,或者向我提问。\r\n\r\n感谢你的一路支持!\r\n\r\n\r\n📢 如果给我发邮件,或者通过微信添加好友,请写上您的**真名实姓**,让我感受到一个**真实的人的气息**。我不太愿意跟**网名**打交道,对于那些不知来路、上来就问问题的微信和邮件,我通常会直接忽略。\r\n\r\n- 微信:**ishenweiyan**(请备注真实姓名,谢谢)\r\n- 邮箱:**shen@weiyan.tech**\r\n\r\n

\r\n feedback\r\n

', 'bodyText': '如果你通过本人的博文/平台学到了一点东西,那么对我最好的奖赏就是请你也尝试教我些东西。你可以通过邮箱、微信,或者移步到 “GitHub Discussions” 写下您的建议,或者向我提问。\n感谢你的一路支持!\n📢 如果给我发邮件,或者通过微信添加好友,请写上您的真名实姓,让我感受到一个真实的人的气息。我不太愿意跟网名打交道,对于那些不知来路、上来就问问题的微信和邮件,我通常会直接忽略。\n\n微信:ishenweiyan(请备注真实姓名,谢谢)\n邮箱:shen@weiyan.tech', 'bodyHTML': '

如果你通过本人的博文/平台学到了一点东西,那么对我最好的奖赏就是请你也尝试教我些东西。你可以通过邮箱、微信,或者移步到 “GitHub Discussions” 写下您的建议,或者向我提问。

\n

感谢你的一路支持!

\n

📢 如果给我发邮件,或者通过微信添加好友,请写上您的真名实姓,让我感受到一个真实的人的气息。我不太愿意跟网名打交道,对于那些不知来路、上来就问问题的微信和邮件,我通常会直接忽略。

\n
    \n
  • 微信:ishenweiyan(请备注真实姓名,谢谢)
  • \n
  • 邮箱:shen@weiyan.tech
  • \n
\n

\n feedback\n

', 'author': {'login': 'shenweiyan'}, 'category': {'name': 'x.x-留言'}, 'labels': {'nodes': []}, 'comments': {'nodes': [{'body': '想了一下,还是增加一个留言的页面吧 >.<', 'author': {'login': 'shenweiyan'}}, {'body': 'hello', 'author': {'login': 'vbskycn'}}, {'body': '我也去整个webstack导航~~ 一入hugo深似海,从此wp是路人。', 'author': {'login': 'daoyuc'}}]}}, {'title': '基于 GitHub Discussions 的博客与站点', 'number': 15, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/15', 'createdAt': '2023-11-09T05:38:01Z', 'lastEditedAt': '2023-11-23T07:06:53Z', 'updatedAt': '2024-01-04T05:44:37Z', 'body': 'GitHub Discussions 是一个可以在每个 GitHub 仓库上启用的论坛。它使开发者能够轻松地讨论新功能,从社区获得反馈,创建投票,发布公告等。这里搜集了一些基于 GitHub Discussions 的博客与站点,以供参考。\r\n\r\n\r\n\r\n- [Hakuba](https://github.com/YeungKC/Hakuba) - 一个通过 Github Discussion 驱动的 Blog 启动器\r\n\r\n- [GG](https://github.com/lencx/gg) - Gatsby + GitHub,好像不支持 MathJax,也不见怎么维护了\r\n - [lencx.tech](https://lencx.tech/#/)\r\n - [gg-discussions](https://shenweiyan.github.io/gg-discussions/),个人尝试对页面进行了一些调整\r\n\r\n- [Pure](https://github.com/LeetaoGoooo/pure) 一个基于 Github Discussion 的极简博客', 'bodyText': 'GitHub Discussions 是一个可以在每个 GitHub 仓库上启用的论坛。它使开发者能够轻松地讨论新功能,从社区获得反馈,创建投票,发布公告等。这里搜集了一些基于 GitHub Discussions 的博客与站点,以供参考。\n\n\n\nHakuba - 一个通过 Github Discussion 驱动的 Blog 启动器\n\n\nGG - Gatsby + GitHub,好像不支持 MathJax,也不见怎么维护了\n\nlencx.tech\ngg-discussions,个人尝试对页面进行了一些调整\n\n\n\nPure 一个基于 Github Discussion 的极简博客', 'bodyHTML': '

GitHub Discussions 是一个可以在每个 GitHub 仓库上启用的论坛。它使开发者能够轻松地讨论新功能,从社区获得反馈,创建投票,发布公告等。这里搜集了一些基于 GitHub Discussions 的博客与站点,以供参考。

\n\n
    \n
  • \n

    Hakuba - 一个通过 Github Discussion 驱动的 Blog 启动器

    \n
  • \n
  • \n

    GG - Gatsby + GitHub,好像不支持 MathJax,也不见怎么维护了

    \n\n
  • \n
  • \n

    Pure 一个基于 Github Discussion 的极简博客

    \n
  • \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '基于 Mkdocs 的主题与站点', 'number': 14, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/14', 'createdAt': '2023-11-08T03:29:49Z', 'lastEditedAt': '2024-06-03T03:28:50Z', 'updatedAt': '2024-06-03T03:28:50Z', 'body': "鉴于 MkDocs 的诸多优点,让它被很多知名开源项目选中,用于搭建和项目相关的文档网站。比如 Python 里知名的 Web 圈里的 [django-rest-framework](https://sspai.com/link?target=https%3A%2F%2Fwww.django-rest-framework.org%2F)、[FastAPI](https://sspai.com/link?target=https%3A%2F%2Ffastapi.tiangolo.com%2F) 以及基于 Go 编写的云网关代理服务器 [traefik](https://sspai.com/link?target=https%3A%2F%2Fgithub.com%2Ftraefik%2Ftraefik) 等项目的官方文档站点,都是通过 MkDocs 进行搭建。\r\n\r\n\r\n\r\n下面列的是搜集的一些 Mkdocs 主题与站点,以供参考。\r\n\r\n- Hello 算法 - \r\n- FDU-MSC 论坛 - \r\n- Django REST framework - \r\n- FastAPI - \r\n- Chrisjing 的运维之旅精选 - \r\n- 艇仔粥 TingZaiZuk - \r\n- Arisa | Blog - \r\n- 嬉戏实验室 - \r\n- 老胡的周刊 - [weekly.howie6879.com](https://weekly.howie6879.com/)\r\n- Wcowin's Web - \r\n- Jeremy Feng - \r\n- 我的工作学习生活笔记 - \r\n- Power's Wiki - ", 'bodyText': "鉴于 MkDocs 的诸多优点,让它被很多知名开源项目选中,用于搭建和项目相关的文档网站。比如 Python 里知名的 Web 圈里的 django-rest-framework、FastAPI 以及基于 Go 编写的云网关代理服务器 traefik 等项目的官方文档站点,都是通过 MkDocs 进行搭建。\n\n下面列的是搜集的一些 Mkdocs 主题与站点,以供参考。\n\nHello 算法 - https://www.hello-algo.com/\nFDU-MSC 论坛 - https://fdu-msc.github.io/forum/\nDjango REST framework - https://www.django-rest-framework.org/\nFastAPI - https://fastapi.tiangolo.com/\nChrisjing 的运维之旅精选 - http://www.chrisjing.com/\n艇仔粥 TingZaiZuk - https://herointene.github.io/\nArisa | Blog - https://blog.arisa.moe/\n嬉戏实验室 - https://blog.xiiigame.com/\n老胡的周刊 - weekly.howie6879.com\nWcowin's Web - https://wcowin.work/\nJeremy Feng - https://fengchao.pro/\n我的工作学习生活笔记 - https://hellowac.github.io/\nPower's Wiki - https://wiki-power.com/", 'bodyHTML': '

鉴于 MkDocs 的诸多优点,让它被很多知名开源项目选中,用于搭建和项目相关的文档网站。比如 Python 里知名的 Web 圈里的 django-rest-frameworkFastAPI 以及基于 Go 编写的云网关代理服务器 traefik 等项目的官方文档站点,都是通过 MkDocs 进行搭建。

\n\n

下面列的是搜集的一些 Mkdocs 主题与站点,以供参考。

\n', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': [{'name': 'mkdocs'}]}, 'comments': {'nodes': []}}, {'title': 'Python3 源码安装', 'number': 13, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/13', 'createdAt': '2023-11-02T03:05:46Z', 'lastEditedAt': '2024-10-14T09:15:08Z', 'updatedAt': '2024-10-14T09:15:09Z', 'body': '编程,作为生物信息学的一个基础性技能,是任何一个生信工程师都无法绕开话题。也许有些人还在纠结 Perl 和 Python 到底应该学习哪一个,但作为目前最火最流行的编程语言 Python 还是非常值得尝试的。它不但可以进行文本处理,在统计、网站、游戏、爬虫、数据可视化等方面也有非常强大的应用,比起曾经的 Perl 真的强大和全面很多,且比 Perl 更容易入手。不管从长远发展,还是短期需要,学会 Python,看懂 Perl (或者先学 \xa0 Python,后学 Perl) 应该是每一个生信工程必备的基础技能之一。\r\n\r\n工欲善其事,必先利其器。关于 Python 安装教程在网上一搜一大把,但总感觉不够全面,尤其对于中间出现的一些问题的解决方法不尽如人意。鉴于此,本文基于 \xa0CentOS/RHEL Linux 对 Python 的源码编译安装进行了一下简单的总结,记录如下。\r\n\r\n## 安装环境\r\n\r\nRed Hat 6.5 + GCC 4.4.7(GCC-7.3.0 - 此版本 gcc 为手动安装)。\r\n\r\nGCC 高级版本手动或者 `yum` 安装参考以下文章:\r\n- [SCL+Devtoolset 安装与使用笔记 · 语雀](https://www.yuque.com/shenweiyan/cookbook/scl-devtoolset-note)\r\n- [非 root 用户手动编译安装 GCC · 语雀](https://www.yuque.com/shenweiyan/cookbook/linux-gcc-install)\r\n\r\n```bash\r\n$ lsb_release -a\r\nLSB Version: :base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noarch:graphics-4.0-amd64:graphics-4.0-noarch:printing-4.0-amd64:printing-4.0-noarch\r\nDistributor ID: RedHatEnterpriseServer\r\nDescription: Red Hat Enterprise Linux Server release 6.5 (Santiago)\r\nRelease: 6.5\r\nCodename: Santiago\r\n\r\n$ gcc --version\r\ngcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-4)\r\nCopyright (C) 2010 Free Software Foundation, Inc.\r\nThis is free software; see the source for copying conditions. There is NO\r\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\r\n```\r\n\r\n## 解决依赖\r\n\r\n如果您拥有 root 权限,请执以下依赖安装:\r\n\r\n```bash\r\nyum install zlib\r\nyum install zlib-devel\r\nyum install openssl\r\nyum install openssl-devel\r\nyum install libffi\r\nyum install libffi-devel\r\nyum install readline readline-devel sqlite sqlite-devel tk-devel\r\n```\r\n\r\n| 缺少库名称 | 安装命令 |\r\n| ---------- | ----------------------------------------------------- |\r\n| \\_uuid | yum install libuuid-devel |\r\n| readline | yum install readline-devel |\r\n| \\_tkinter | yum install tk-devel |\r\n| \\_ffi | yum install libffi-devel |\r\n| \\_curses | yum install ncurses-libs |\r\n| \\_sqlite | yum install sqlite-devel |\r\n| \\_bz2 | yum isntall bzip2-devel |\r\n| \\_ssl | yum install openssl-devel |\r\n| \\_gdbm | yum install gdbm-devel |\r\n| \\_dbi | yum install libdbi-devel |\r\n| \\_zlib | yum install zlib-devel |\r\n| lzma | yum install xz-develyum install python-backports-lzma |\r\n\r\n如果您没有 root 权限,可以参考《[手把手教你在 Linux 源码安装最新版本的 R](https://www.yuque.com/shenweiyan/cookbook/install-latest-r-from-source)》一文,手动一个个去解决以上的依赖。\r\n\r\n### _sqlite3 \r\n\r\n执行 **make** 过程中提示 **_sqlite3 not found**,如下:\r\n\r\n```bash\r\n$ make\r\n......\r\nPython build finished successfully!\r\nThe necessary bits to build these optional modules were not found:\r\n_sqlite3 _ssl\r\nTo find the necessary bits, look in setup.py in detect_modules() for the module\'s name.\r\n\r\nThe following modules found by detect_modules() in setup.py, have been\r\nbuilt by the Makefile instead, as configured by the Setup files:\r\n_abc atexit pwd\r\ntime\r\n```\r\n\r\n#### 系统已安装 sqlite3\r\n\r\n如果执行 **rpm -qa|grep sqlite** 看到 sqlite 和 sqlite-devel 都已经安装(libsqlite3.so 默认保存在 /usr/lib64 下; `sqlite3.h` 默认保存在 `/usr/include` 下)。\r\n\r\n```bash\r\n$ sqlite3 -version\r\n3.6.20\r\n\r\n$ ll /usr/lib64/libsqlite3.so\r\nlrwxrwxrwx 1 root root 19 Apr 23 2015 /usr/lib64/libsqlite3.so -> libsqlite3.so.0.8.6\r\n\r\n$ ll /usr/include/sqlite3.h\r\n-rw-r--r-- 1 root root 263K Nov 25 2009 /usr/include/sqlite3.h\r\n```\r\n\r\n但是,执行 `make` 依然出现以上报错,参考下面的方法《[python build from source: cannot build optional module sqlite3 - Stack Overflow](https://stackoverflow.com/questions/32779768/python-build-from-source-cannot-build-optional-module-sqlite3)》。\r\n\r\n#### 手动安装 sqlite3\r\n\r\n```bash\r\n$ wget https://www.sqlite.org/2021/sqlite-autoconf-3360000.tar.gz --no-check-certificate\r\n$ tar zvxf sqlite-autoconf-3360000.tar.gz\r\n$ cd sqlite-autoconf-3360000\r\n$ ./configure --prefix=/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0\r\n$ make\r\n$ make install\r\n```\r\n\r\n#### 配置 sqlite3\r\n\r\n1. 配置环境\r\n\r\n```bash\r\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/lib:$LD_LIBRARY_PATH\r\n```\r\n2. 调整源码或编译\r\n\r\n对于 3.11.x 以上版本的 Python 可以在 `configure` 指定自定义安装的 sqlite3 路径解决 `_sqlite3` 依赖。\r\n```\r\n./configure ... \\\r\n LDFLAGS="-L/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/lib" \\\r\n CPPFLAGS="-I/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/include" \r\n```\r\n\r\n有些低版本的 Python (如 3.7) 可能需要再源码文件中加入 `sqlite3.h` 的文件路径。\r\n\r\n1. 找到 **sqlite3.h** 文件的保存目录。\r\n2. 修改 **setup.py** 文件,在 sqlite_inc_paths 中加上 sqlite3.h 的文件路径。\r\n\r\n```bash\r\nsqlite_inc_paths = [ \'/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/include\',\r\n \'/usr/include\',\r\n \'/usr/include/sqlite\',\r\n \'/usr/include/sqlite3\',\r\n \'/usr/local/include\',\r\n \'/usr/local/include/sqlite\',\r\n \'/usr/local/include/sqlite3\',\r\n ]\r\n```\r\n\r\n\r\n### _ssl \r\n\r\nPython3 需要引用 `openssl`\xa0 模块,但是 python3.7+ 在 CentOS 中要求的 openssl 版本最低为 1.0.2,而 CentOS 默认的为 1.0.1(CentOS-6.x 通过 `yum`\xa0 源安装的 openssl 的最高版本是 1.0.1),所以需要手动更新 openssl。\r\n\r\n对于 openssl 版本的选择,建议至少选择 1.1.1+ 版本:\r\n\r\n1. urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the \'ssl\' module is compiled with \'OpenSSL 1.0.2k-fips 26 Jan 2017\'. See: https://github.com/urllib3/urllib3/issues/2168\r\n2. **Python requires an OpenSSL 1.0.2 or 1.1 compatible libssl with X509_VERIFY_PARAM_set1_host().**\r\n\r\n```bash\r\n# 下载\r\nwget http://www.openssl.org/source/openssl-1.1.1.tar.gz\r\n\r\n# 解压缩\r\ntar -zxvf openssl-1.1.1.tar.gz\r\n\r\n# 进入目录安装\r\ncd openssl-1.1.1\r\n\r\n# 进行配置下,自定义\r\n./config --prefix=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1 shared zlib\r\n\r\n# 编译并安装\r\nmake && make install\r\n\r\n# 配置到用户环境变量,随处使用\r\necho "export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1/lib:$LD_LIBRARY_PATH" >> $HOME/.bashrc\r\n\r\n# 是环境变量配置生效\r\nsource $HOME/.bashrc\r\n```\r\n\r\n**请注意:**\r\n\r\n1. **openssl**\xa0编译(config)的时候 **必须要加上 shared\xa0 参数**,否者源码安装 Python 即使添加了 `--with-openssl`\xa0的自定义路径,依然会导致 `Could not build the ssl module!`\xa0报错!\r\n2. 从 \xa0下载的源码 openssl-1.0.2s、openssl-1.0.2m,包括 \xa0CentOS-7.5 使用 `yum`\xa0安装的最高版本的 openssl-1.0.2k 目前发现依然会导致 `Could not build the ssl module`\xa0,建议从 \xa0下载 1.1.1 的源码编译安装。\r\n\r\n最后,在 Python 执行 `configure` 的时候指定 openssl 的相关参数:\r\n```\r\n./configure ... \\\r\n --with-openssl=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1 \\\r\n --with-openssl-rpath=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1/lib \\\r\n```\r\n\r\n### _tkinter\r\n\r\nTkinter 模块缺失是一个比较棘手的问题,为此专门写了一篇文章来介绍这个问题。\r\n\r\n具体请参考:[Python 中 tkinter 源码安装使用与中文乱码 - Knowledge-Garden#12](https://github.com/shenweiyan/Knowledge-Garden/discussions/12)\r\n\r\n### _dbm\r\n\r\n`_dbm` 和 `_gdbm` 的模块缺失可以通过下面手动的方法解决。\r\n\r\n```\r\nwget https://ftp.gnu.org/gnu/gdbm/gdbm-1.23.tar.gz\r\ntar -zxvf gdbm-1.23.tar.gz\r\n./configure --prefix=/Bioinfo/Pipeline/SoftWare/gdbm-1.23 --enable-libgdbm-compat --enable-debug\r\nmake && make install\r\n```\r\n\r\n最后,增加环境变量,并调整 Python 执行 `configure` 时的参数:\r\n```\r\nexport PATH=/Bioinfo/Pipeline/SoftWare/gdbm-1.23/bin:$PATH\r\nexport LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/gdbm-1.23/lib:$LD_LIBRARY_PATH\r\n\r\n./configure ... \\\r\n LDFLAGS="-L/Bioinfo/Pipeline/SoftWare/gdbm-1.23/lib" \\\r\n CPPFLAGS="-I/Bioinfo/Pipeline/SoftWare/gdbm-1.23/include"\r\n```\r\n\r\n### _lzma \r\n\r\n正常情况下,下面的方法可以解决该问题(如果您有 root 权限的话)。\r\n\r\n```bash\r\n# For ubuntu:\r\n$ sudo apt-get install liblzma-dev\r\n\r\n# For centos:\r\n$ yum install xz-devel\r\n```\r\n\r\n普通用户可以手动安装解决:\r\n\r\n```bash\r\n$ wget https://tukaani.org/xz/xz-5.2.5.tar.gz --no-check-certificat\r\n$ tar zvxf xz-5.2.5.tar.gz\r\n$ cd xz-5.2.5\r\n$ ./configure --prefix=/Bioinfo/Pipeline/SoftWare/xz-5.2.5\r\n$ make\r\n$ make install\r\n```\r\n\r\n最后,配置环境:\r\n\r\n```bash\r\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/xz-5.2.5/lib:$LD_LIBRARY_PATH\r\n```\r\n\r\n### _ctypes \r\n\r\n在 CentOS 6.x 安装 `libffi-devel`\xa0 的时候出现以下问题:\r\n\r\n```bash\r\n$ yum install libffi-devel\r\nLoaded plugins: product-id, refresh-packagekit, search-disabled-repos, security, subscription-manager\r\nThis system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.\r\nSetting up Install Process\r\ncdrom | 4.1 kB 00:00 ...\r\nNo package libffi-devel available.\r\nError: Nothing to do\r\n```\r\n\r\n可以使用下面的方法安装:\r\n```shell\r\n[root@log01 ~]# rpm -ivh http://mirror.centos.org/centos/6/os/x86_64/Packages/libffi-devel-3.0.5-3.2.el6.x86_64.rpm\r\nRetrieving http://mirror.centos.org/centos/6/os/x86_64/Packages/libffi-devel-3.0.5-3.2.el6.x86_64.rpm\r\nwarning: /var/tmp/rpm-tmp.V9ihbu: Header V3 RSA/SHA256 Signature, key ID c105b9de: NOKEY\r\nPreparing... ########################################### [100%]\r\n 1:libffi-devel ########################################### [100%]\r\n[root@log01 ~]# rpm -qa|grep libffi\r\nlibffi-3.0.5-3.2.el6.x86_64\r\nlibffi-devel-3.0.5-3.2.el6.x86_64\r\n```\r\n\r\n手动的源码方法安装如下:\r\n```bash\r\n$ wget ftp://sourceware.org/pub/libffi/libffi-3.2.1.tar.gz\r\n$ tar zvxf libffi-3.2.1.tar.gz\r\n$ ./configure --prefix=/Bioinfo/Pipeline/SoftWare/libffi-3.2.1\r\n$ make\r\n$ make install\r\n```\r\n\r\n### pygraphviz\r\n\r\n如果你不需要使用 pygraphviz,可以不用管这个依赖。\r\n\r\n> PyGraphviz is a Python interface to the Graphviz graph layout and visualization package. With PyGraphviz you can create, edit, read, write, and draw graphs using Python to access the Graphviz graph data structure and layout algorithms.\r\n\r\n> PyGraphviz 是 Graphviz 图形布局和可视化包的 Python 接口。 借助 PyGraphviz,您可以使用 Python 创建、编辑、读取、写入和绘制图形,以访问 Graphviz 图形数据结构和布局算法。\r\n\r\n```bash\r\n$ /Bioinfo/Pipeline/SoftWare/Python-3.7.3/bin/pip3 install pygraphviz\r\nCollecting pygraphviz\r\n Using cached https://files.pythonhosted.org/packages/7e/b1/d6d849ddaf6f11036f9980d433f383d4c13d1ebcfc3cd09bc845bda7e433/pygraphviz-1.5.zip\r\nInstalling collected packages: pygraphviz\r\n Running setup.py install for pygraphviz ... error\r\n Complete output from command /Bioinfo/Pipeline/SoftWare/Python-3.7.3/bin/python3.7 -u -c "import setuptools, tokenize;__file__=\'/tmp/pip-install-_zdjdg0j/pygraphviz/setup.py\';f=getattr(tokenize, \'open\', open)(__file__);code=f.read().replace(\'\\r\\n\', \'\\n\');f.close();exec(compile(code, __file__, \'exec\'))" install --record /tmp/pip-record-g0mz7lrq/install-record.txt --single-version-externally-managed --compile:\r\n running install\r\n Trying dpkg\r\n Failed to find dpkg\r\n Trying pkg-config\r\n Package libcgraph was not found in the pkg-config search path.\r\n Perhaps you should add the directory containing `libcgraph.pc\'\r\n to the PKG_CONFIG_PATH environment variable\r\n No package \'libcgraph\' found\r\n Traceback (most recent call last):\r\n File "", line 1, in \r\n File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup.py", line 93, in \r\n tests_require=[\'nose>=1.3.7\', \'doctest-ignore-unicode>=0.1.2\', \'mock>=2.0.0\'],\r\n File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/site-packages/setuptools/__init__.py", line 145, in setup\r\n return distutils.core.setup(**attrs)\r\n File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/distutils/core.py", line 148, in setup\r\n dist.run_commands()\r\n File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/distutils/dist.py", line 966, in run_commands\r\n self.run_command(cmd)\r\n File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/distutils/dist.py", line 985, in run_command\r\n cmd_obj.run()\r\n File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup_commands.py", line 44, in modified_run\r\n self.include_path, self.library_path = get_graphviz_dirs()\r\n File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup_extra.py", line 162, in get_graphviz_dirs\r\n include_dirs, library_dirs = _try_configure(include_dirs, library_dirs, _pkg_config)\r\n File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup_extra.py", line 117, in _try_configure\r\n i, l = try_function()\r\n File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup_extra.py", line 72, in _pkg_config\r\n output = S.check_output([\'pkg-config\', \'--libs-only-L\', \'libcgraph\'])\r\n File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/subprocess.py", line 395, in check_output\r\n **kwargs).stdout\r\n File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/subprocess.py", line 487, in run\r\n output=stdout, stderr=stderr)\r\n subprocess.CalledProcessError: Command \'[\'pkg-config\', \'--libs-only-L\', \'libcgraph\']\' returned non-zero exit status 1.\r\n\r\n ----------------------------------------\r\nCommand "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/bin/python3.7 -u -c "import setuptools, tokenize;__file__=\'/tmp/pip-install-_zdjdg0j/pygraphviz/setup.py\';f=getattr(tokenize, \'open\', open)(__file__);code=f.read().replace(\'\\r\\n\', \'\\n\');f.close();exec(compile(code, __file__, \'exec\'))" install --record /tmp/pip-record-g0mz7lrq/install-record.txt --single-version-externally-managed --compile" failed with error code 1 in /tmp/pip-install-_zdjdg0j/pygraphviz/\r\n\r\n```\r\n\r\n参考:《[Installation:fatal error: \'graphviz/cgraph.h\' file not found](https://github.com/pygraphviz/pygraphviz/issues/11)》\r\n\r\n```bash\r\n$ wget https://graphviz.gitlab.io/pub/graphviz/stable/SOURCES/graphviz.tar.gz\r\n$ tar zvxf graphviz.tar.gz\r\n$ cd graphviz-2.40.1\r\n$ ./configure --prefix=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1\r\n$ make && make install\r\n```\r\n\r\n推荐把安装好的 graphviz 添加到环境变量,这样可以避免运行过程中出现:**"pygraphviz/graphviz_wrap.c:2987:29: fatal error: graphviz/cgraph.h: No such file or directory"** 无法找到头文件的异常。\r\n\r\n```bash\r\nexport PKG_CONFIG_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib/pkgconfig:$PKG_CONFIG_PATH\r\nexport LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib:$LD_LIBRARY_PATH\r\nexport C_INCLUDE_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/include:$C_INCLUDE_PATH\r\nexport CPLUS_INCLUDE_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/include:$CPLUS_INCLUDE_PATH\r\n```\r\n\r\n如果 graphviz 添加到环境变量, `pygraphviz`\xa0的 python 包可以参考下面的方法安装:\r\n\r\n```bash\r\n$ /Bioinfo/Pipeline/SoftWare/Python-3.7.3/bin/pip3 install --global-option=build_ext --global-option="-I/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/include" --global-option="-L/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib" pygraphviz\r\n/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/site-packages/pip/_internal/commands/install.py:207: UserWarning: Disabling all use of wheels due to the use of --build-options / --global-options / --install-options.\r\n cmdoptions.check_install_build_global(options)\r\nCollecting pygraphviz\r\n Using cached https://files.pythonhosted.org/packages/7e/b1/d6d849ddaf6f11036f9980d433f383d4c13d1ebcfc3cd09bc845bda7e433/pygraphviz-1.5.zip\r\nInstalling collected packages: pygraphviz\r\n Running setup.py install for pygraphviz ... done\r\nSuccessfully installed pygraphviz-1.5\r\n```\r\n\r\n## 编译安装\r\n\r\n这里的编译安装,以 Python-3.11.6 为示例。\r\n\r\n第一,下载 Python 源码,解压。\r\n\r\n```bash\r\n# 官网下载地址 https://www.python.org/downloads\r\nwget https://www.python.org/ftp/python/3.11.6/Python-3.11.6.tgz\r\n\r\n# 解压到指定目录\r\ntar zvxf Python-3.11.6.tgz -C /usr/local/src\r\n```\r\n\r\n第二,进入解压的源码路径,编译 Python 源码。\r\n\r\n```bash\r\n$ export PKG_CONFIG_PATH=/Bioinfo/Pipeline/SoftWare/libffi-3.2.1/lib/pkgconfig:$PKG_CONFIG_PATH\r\n$ export PKG_CONFIG_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib/pkgconfig:$PKG_CONFIG_PATH\r\n\r\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/libffi-3.2.1/lib64:$LD_LIBRARY_PATH\r\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib:$LD_LIBRARY_PATH\r\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1/lib:$LD_LIBRARY_PATH\r\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/lib:$LD_LIBRARY_PATH\r\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/gdbm-1.23/lib:$LD_LIBRARY_PATH\r\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/lib:$LD_LIBRARY_PATH\r\n\r\n$ export TCLTK_LIBS="-L/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/lib -ltcl8.6 -ltk8.6"\r\n$ export TCLTK_CFLAGS="-I/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/include"\r\n\r\n$ ./configure \\\r\n--enable-optimizations \\\r\n--prefix=/Bioinfo/Pipeline/SoftWare/Python-3.11.6 \\\r\n--with-openssl=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1 \\\r\n--with-openssl-rpath=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1/lib \\\r\nCC=/Bioinfo/Pipeline/SoftWare/gcc-7.3.0/bin/gcc \\\r\nCXX=/Bioinfo/Pipeline/SoftWare/gcc-7.3.0/bin/c++ \\\r\nLDFLAGS="-L/Bioinfo/Pipeline/SoftWare/libffi-3.2.1/lib64 \\\r\n -L/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib \\\r\n -L/RiboBio/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/lib \\\r\n -L/Bioinfo/Pipeline/SoftWare/gdbm-1.23/lib" \\\r\nCPPFLAGS="-I/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/include \\\r\n -I/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/include \\\r\n -I/Bioinfo/Pipeline/SoftWare/gdbm-1.23/include" \\\r\nPKG_CONFIG_PATH="/Bioinfo/Pipeline/SoftWare/libffi-3.2.1/lib/pkgconfig: \\\r\n /Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib/pkgconfig"\r\n```\r\n\r\n- `--enable-optimizations`\xa0 是优化选项(LTO,PGO\xa0 等)加上这个 \xa0flag\xa0 编译后,性能有 \xa010%\xa0 左右的优化,但是这会明显的增加编译时间。建议使用这个参数;\r\n- `--prefix`\xa0 声明安装路径;\r\n- 安装多个 python 的版本,如果不开启`--enable-shared`,指定不同路径即可。当开启`--enable-shared` 时,默认只有一个版本的 python。\r\n- Python 3 编译可以在 configure 或者环境变量中指定 OpenSSL 安装路径进行编译的方式解决 OpenSSL 依赖,否则 `make`\xa0 过程可能出错。\r\n\r\n```shell\r\n$ make\r\n......\r\nThe following modules found by detect_modules() in setup.py, have been\r\nbuilt by the Makefile instead, as configured by the Setup files:\r\n_abc atexit pwd\r\ntime\r\n\r\n\r\nFailed to build these modules:\r\n_ctypes _hashlib _ssl\r\n\r\n\r\nCould not build the ssl module!\r\nPython requires an OpenSSL 1.0.2 or 1.1 compatible libssl with X509_VERIFY_PARAM_set1_host().\r\nLibreSSL 2.6.4 and earlier do not provide the necessary APIs, https://github.com/libressl-portable/portable/issues/381\r\n\r\n......\r\n```\r\n\r\n- `make`\xa0过程如果出现 `ModuleNotFoundError: No module named \'_ctypes\'`\xa0或者 `INFO: Could not locate ffi libs and/or headers`\xa0参考:\r\n\r\n![image.png](https://shub.weiyan.tech/yuque/elog-cookbook-img/FmK7bCeEeGjfbl1UVdvHyw3Jg8Zj.png)\r\n\r\n- 对于低版本的 Python 如果指定\xa0`--with-openssl=DIR`\xa0依然无法解决 ssl 模块的问题,可以参考修改 Modules/Setup.dist 文件(默认这块是注释的,放开注释即可。这块功能是开启 SSL 模块,不然会出现安装完毕后,提示找不到 ssl 模块的错误)再执行 configure,修改内容如下:\r\n\r\n```bash\r\n# Socket module helper for SSL support; you must comment out the other\r\n# socket line above, and possibly edit the SSL variable:\r\nSSL=/usr/local/ssl\r\n_ssl _ssl.c \\\r\n -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \\\r\n -L$(SSL)/lib -lssl -lcrypto\r\n```\r\n\r\n第三,Makefile 生后依次在当前路径执行编译和安装命令。\r\n\r\n```bash\r\nmake && make install\r\n```\r\n\r\n第四,安装完成。以上命令执行完毕,且无报错的情况下,我们将默认 python 换将切换至 3.11.6(一般不建议替换,个人建议把自定义安装的 Python bin 路径添加到 PATH 环境变量即可):\r\n\r\n```bash\r\n# 替换系统自带的 python(不建议)\r\nmv /usr/bin/python /usr/bin/python2\r\nln -s /Bioinfo/Pipeline/SoftWare/Python-3.11.6/bin/python3 /usr/bin/python3\r\n\r\n# 添加新 Python 到 PATH 环境变量(建议)\r\necho "export PATH=/Bioinfo/Pipeline/SoftWare/Python-3.11.6/bin:$PATH" >>~/.bashrc\r\nsource ~/.bashrc\r\n```\r\n\r\n运行命令 `python -V`\xa0,查看是否出现 3.11.6\xa0 的版本,出现即为安装成功。\r\n\r\n## 其他工具\r\n\r\nPython >= 3.10 在安装时候,默认会同时安装 **pip3**!如果你的 python < 3.10,可以参考下面的方法安装 pip。\r\n\r\n```bash\r\n# 下载 setuptools 和 pip 安装程序\r\ncurl https://bootstrap.pypa.io/get-pip.py -o get-pip.py\r\npython3 get-pip.py\r\n```\r\n\r\n至此,CentOS Linux release\xa06.5 下的 python-3.11.6\xa0 全部安装完成。如果在安装过程中出现其他的报错,建议把 error 关键信息直接复制到 Google 进行检索,参考其他人的解决方法。\r\n\r\n## 其他异常与解决\r\n\r\n### _bz2\r\n\r\n- 系统:CentOS Linux release 7.7.1908 (Core)\r\n- GCC:gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39)\r\n\r\n在 CentOS 7 中安装 Python-3.6.9 中发现 make 过程中一直提示:"**ModuleNotFoundError: No module named \'_bz2\'**",尽管 `sudo yum install bzip2 bzip2-devel`\xa0 已经安装了 bzip2 的依赖,问题还是不得其解。最后参考 stackoverflow 上的《Correctly building local python3, with bz2 support》,终于解决问题,下面记录一下。\r\n[Correctly building local python3, with bz2 support](https://stackoverflow.com/questions/51149227/correctly-building-local-python3-with-bz2-support)\r\n\r\n**手动安装 bzip2:**\r\n\r\n```bash\r\nwget https://nchc.dl.sourceforge.net/project/bzip2/bzip2-1.0.6.tar.gz\r\ntar zvxf bzip2-1.0.6.tar.gz\r\ncd bzip2-1.0.6\r\nmake -f Makefile_libbz2_so # 这一步是生成 libbz2.so.1.0.6 的动态库文件\r\nmake\r\nmake install PREFIX=/usr/local/software/bzip2-1.0.6\r\ncp libbz2.so.1.0.6 /usr/local/software/bzip2-1.0.6/lib/\r\n```\r\n\r\n**几点说明:**\r\n\r\n- bzip2 的官网 \xa0\xa0 已经把 bzip2 的源码下载链接放到了 \xa0SourceForge,网络上一些从 \xa0\xa0 下载的做法已经失效。\r\n- [SourceForge](https://sourceforge.net/projects/bzip2/files/) 上 bzip2 的最新版本还是 1.0.6(Last modified 2018-11-3),更高级版本的 bzip2 我也不知道是否存在,也不知道能不能用。\r\n\r\n![image.png](https://shub.weiyan.tech/yuque/elog-cookbook-img/FvgxGWlVJSxOCvgXFo9BPOa3ODm5.png)\r\n\r\n**编译安装 Python-3.6.9:**\r\n\r\n```bash\r\n$ wget https://www.python.org/ftp/python/3.6.9/Python-3.6.9.tgz\r\n$ tar zvxf Python-3.6.9.tgz\r\n$ cd Python-3.6.9\r\n$ ./configure --enable-optimizations --prefix=/usr/local/software/python-3.6 CFLAGS="-I/usr/local/software/bzip2-1.0.6/include" LDFLAGS="-L/usr/local/software/bzip2-1.0.6/lib"\r\n$ make\r\n$ make install\r\n```\r\n\r\n- Python-3.6.9 中的 `./configure --help`\xa0中没有 `--with-openssl`\xa0参数!有点神奇,我也不知道原因。\r\n- 安装完成可以用 `from _bz2 import BZ2Compressor, BZ2Decompressor`\xa0测试一下 `_bz2`\xa0 是否可用。\r\n\r\n\r\n## 参考资料\r\n\r\n1. 行者无疆-ITer,《[python2.7 源码编译安装](https://www.cnblogs.com/ITer-jack/p/8305912.html)》, 博客园\r\n2. Scott Frazer,《[How do I compile Python 3.4 with custom OpenSSL?](https://stackoverflow.com/questions/23548188/how-do-i-compile-python-3-4-with-custom-openssl)》, Stack Overflow\r\n', 'bodyText': '编程,作为生物信息学的一个基础性技能,是任何一个生信工程师都无法绕开话题。也许有些人还在纠结 Perl 和 Python 到底应该学习哪一个,但作为目前最火最流行的编程语言 Python 还是非常值得尝试的。它不但可以进行文本处理,在统计、网站、游戏、爬虫、数据可视化等方面也有非常强大的应用,比起曾经的 Perl 真的强大和全面很多,且比 Perl 更容易入手。不管从长远发展,还是短期需要,学会 Python,看懂 Perl (或者先学 \xa0 Python,后学 Perl) 应该是每一个生信工程必备的基础技能之一。\n工欲善其事,必先利其器。关于 Python 安装教程在网上一搜一大把,但总感觉不够全面,尤其对于中间出现的一些问题的解决方法不尽如人意。鉴于此,本文基于 \xa0CentOS/RHEL Linux 对 Python 的源码编译安装进行了一下简单的总结,记录如下。\n安装环境\nRed Hat 6.5 + GCC 4.4.7(GCC-7.3.0 - 此版本 gcc 为手动安装)。\nGCC 高级版本手动或者 yum 安装参考以下文章:\n\nSCL+Devtoolset 安装与使用笔记 · 语雀\n非 root 用户手动编译安装 GCC · 语雀\n\n$ lsb_release -a\nLSB Version: :base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noarch:graphics-4.0-amd64:graphics-4.0-noarch:printing-4.0-amd64:printing-4.0-noarch\nDistributor ID: RedHatEnterpriseServer\nDescription: Red Hat Enterprise Linux Server release 6.5 (Santiago)\nRelease: 6.5\nCodename: Santiago\n\n$ gcc --version\ngcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-4)\nCopyright (C) 2010 Free Software Foundation, Inc.\nThis is free software; see the source for copying conditions. There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n解决依赖\n如果您拥有 root 权限,请执以下依赖安装:\nyum install zlib\nyum install zlib-devel\nyum install openssl\nyum install openssl-devel\nyum install libffi\nyum install libffi-devel\nyum install readline readline-devel sqlite sqlite-devel tk-devel\n\n\n\n缺少库名称\n安装命令\n\n\n\n\n_uuid\nyum install libuuid-devel\n\n\nreadline\nyum install readline-devel\n\n\n_tkinter\nyum install tk-devel\n\n\n_ffi\nyum install libffi-devel\n\n\n_curses\nyum install ncurses-libs\n\n\n_sqlite\nyum install sqlite-devel\n\n\n_bz2\nyum isntall bzip2-devel\n\n\n_ssl\nyum install openssl-devel\n\n\n_gdbm\nyum install gdbm-devel\n\n\n_dbi\nyum install libdbi-devel\n\n\n_zlib\nyum install zlib-devel\n\n\nlzma\nyum install xz-develyum install python-backports-lzma\n\n\n\n如果您没有 root 权限,可以参考《手把手教你在 Linux 源码安装最新版本的 R》一文,手动一个个去解决以上的依赖。\n_sqlite3\n执行 make 过程中提示 _sqlite3 not found,如下:\n$ make\n......\nPython build finished successfully!\nThe necessary bits to build these optional modules were not found:\n_sqlite3 _ssl\nTo find the necessary bits, look in setup.py in detect_modules() for the module\'s name.\n\nThe following modules found by detect_modules() in setup.py, have been\nbuilt by the Makefile instead, as configured by the Setup files:\n_abc atexit pwd\ntime\n系统已安装 sqlite3\n如果执行 rpm -qa|grep sqlite 看到 sqlite 和 sqlite-devel 都已经安装(libsqlite3.so 默认保存在 /usr/lib64 下; sqlite3.h 默认保存在 /usr/include 下)。\n$ sqlite3 -version\n3.6.20\n\n$ ll /usr/lib64/libsqlite3.so\nlrwxrwxrwx 1 root root 19 Apr 23 2015 /usr/lib64/libsqlite3.so -> libsqlite3.so.0.8.6\n\n$ ll /usr/include/sqlite3.h\n-rw-r--r-- 1 root root 263K Nov 25 2009 /usr/include/sqlite3.h\n但是,执行 make 依然出现以上报错,参考下面的方法《python build from source: cannot build optional module sqlite3 - Stack Overflow》。\n手动安装 sqlite3\n$ wget https://www.sqlite.org/2021/sqlite-autoconf-3360000.tar.gz --no-check-certificate\n$ tar zvxf sqlite-autoconf-3360000.tar.gz\n$ cd sqlite-autoconf-3360000\n$ ./configure --prefix=/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0\n$ make\n$ make install\n配置 sqlite3\n\n配置环境\n\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/lib:$LD_LIBRARY_PATH\n\n调整源码或编译\n\n对于 3.11.x 以上版本的 Python 可以在 configure 指定自定义安装的 sqlite3 路径解决 _sqlite3 依赖。\n./configure ... \\\n LDFLAGS="-L/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/lib" \\\n CPPFLAGS="-I/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/include" \n\n有些低版本的 Python (如 3.7) 可能需要再源码文件中加入 sqlite3.h 的文件路径。\n\n找到 sqlite3.h 文件的保存目录。\n修改 setup.py 文件,在 sqlite_inc_paths 中加上 sqlite3.h 的文件路径。\n\nsqlite_inc_paths = [ \'/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/include\',\n \'/usr/include\',\n \'/usr/include/sqlite\',\n \'/usr/include/sqlite3\',\n \'/usr/local/include\',\n \'/usr/local/include/sqlite\',\n \'/usr/local/include/sqlite3\',\n ]\n_ssl\nPython3 需要引用 openssl\xa0 模块,但是 python3.7+ 在 CentOS 中要求的 openssl 版本最低为 1.0.2,而 CentOS 默认的为 1.0.1(CentOS-6.x 通过 yum\xa0 源安装的 openssl 的最高版本是 1.0.1),所以需要手动更新 openssl。\n对于 openssl 版本的选择,建议至少选择 1.1.1+ 版本:\n\nurllib3 v2.0 only supports OpenSSL 1.1.1+, currently the \'ssl\' module is compiled with \'OpenSSL 1.0.2k-fips 26 Jan 2017\'. See: urllib3/urllib3#2168\nPython requires an OpenSSL 1.0.2 or 1.1 compatible libssl with X509_VERIFY_PARAM_set1_host().\n\n# 下载\nwget http://www.openssl.org/source/openssl-1.1.1.tar.gz\n\n# 解压缩\ntar -zxvf openssl-1.1.1.tar.gz\n\n# 进入目录安装\ncd openssl-1.1.1\n\n# 进行配置下,自定义\n./config --prefix=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1 shared zlib\n\n# 编译并安装\nmake && make install\n\n# 配置到用户环境变量,随处使用\necho "export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1/lib:$LD_LIBRARY_PATH" >> $HOME/.bashrc\n\n# 是环境变量配置生效\nsource $HOME/.bashrc\n请注意:\n\nopenssl\xa0编译(config)的时候 必须要加上 shared\xa0 参数,否者源码安装 Python 即使添加了 --with-openssl\xa0的自定义路径,依然会导致 Could not build the ssl module!\xa0报错!\n从 https://www.openssl.org/source/\xa0下载的源码 openssl-1.0.2s、openssl-1.0.2m,包括 \xa0CentOS-7.5 使用 yum\xa0安装的最高版本的 openssl-1.0.2k 目前发现依然会导致 Could not build the ssl module\xa0,建议从 https://www.openssl.org/source/old/\xa0下载 1.1.1 的源码编译安装。\n\n最后,在 Python 执行 configure 的时候指定 openssl 的相关参数:\n./configure ... \\\n --with-openssl=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1 \\\n --with-openssl-rpath=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1/lib \\\n\n_tkinter\nTkinter 模块缺失是一个比较棘手的问题,为此专门写了一篇文章来介绍这个问题。\n具体请参考:Python 中 tkinter 源码安装使用与中文乱码 - Knowledge-Garden#12\n_dbm\n_dbm 和 _gdbm 的模块缺失可以通过下面手动的方法解决。\nwget https://ftp.gnu.org/gnu/gdbm/gdbm-1.23.tar.gz\ntar -zxvf gdbm-1.23.tar.gz\n./configure --prefix=/Bioinfo/Pipeline/SoftWare/gdbm-1.23 --enable-libgdbm-compat --enable-debug\nmake && make install\n\n最后,增加环境变量,并调整 Python 执行 configure 时的参数:\nexport PATH=/Bioinfo/Pipeline/SoftWare/gdbm-1.23/bin:$PATH\nexport LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/gdbm-1.23/lib:$LD_LIBRARY_PATH\n\n./configure ... \\\n LDFLAGS="-L/Bioinfo/Pipeline/SoftWare/gdbm-1.23/lib" \\\n CPPFLAGS="-I/Bioinfo/Pipeline/SoftWare/gdbm-1.23/include"\n\n_lzma\n正常情况下,下面的方法可以解决该问题(如果您有 root 权限的话)。\n# For ubuntu:\n$ sudo apt-get install liblzma-dev\n\n# For centos:\n$ yum install xz-devel\n普通用户可以手动安装解决:\n$ wget https://tukaani.org/xz/xz-5.2.5.tar.gz --no-check-certificat\n$ tar zvxf xz-5.2.5.tar.gz\n$ cd xz-5.2.5\n$ ./configure --prefix=/Bioinfo/Pipeline/SoftWare/xz-5.2.5\n$ make\n$ make install\n最后,配置环境:\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/xz-5.2.5/lib:$LD_LIBRARY_PATH\n_ctypes\n在 CentOS 6.x 安装 libffi-devel\xa0 的时候出现以下问题:\n$ yum install libffi-devel\nLoaded plugins: product-id, refresh-packagekit, search-disabled-repos, security, subscription-manager\nThis system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.\nSetting up Install Process\ncdrom | 4.1 kB 00:00 ...\nNo package libffi-devel available.\nError: Nothing to do\n可以使用下面的方法安装:\n[root@log01 ~]# rpm -ivh http://mirror.centos.org/centos/6/os/x86_64/Packages/libffi-devel-3.0.5-3.2.el6.x86_64.rpm\nRetrieving http://mirror.centos.org/centos/6/os/x86_64/Packages/libffi-devel-3.0.5-3.2.el6.x86_64.rpm\nwarning: /var/tmp/rpm-tmp.V9ihbu: Header V3 RSA/SHA256 Signature, key ID c105b9de: NOKEY\nPreparing... ########################################### [100%]\n 1:libffi-devel ########################################### [100%]\n[root@log01 ~]# rpm -qa|grep libffi\nlibffi-3.0.5-3.2.el6.x86_64\nlibffi-devel-3.0.5-3.2.el6.x86_64\n手动的源码方法安装如下:\n$ wget ftp://sourceware.org/pub/libffi/libffi-3.2.1.tar.gz\n$ tar zvxf libffi-3.2.1.tar.gz\n$ ./configure --prefix=/Bioinfo/Pipeline/SoftWare/libffi-3.2.1\n$ make\n$ make install\npygraphviz\n如果你不需要使用 pygraphviz,可以不用管这个依赖。\n\nPyGraphviz is a Python interface to the Graphviz graph layout and visualization package. With PyGraphviz you can create, edit, read, write, and draw graphs using Python to access the Graphviz graph data structure and layout algorithms.\n\n\nPyGraphviz 是 Graphviz 图形布局和可视化包的 Python 接口。 借助 PyGraphviz,您可以使用 Python 创建、编辑、读取、写入和绘制图形,以访问 Graphviz 图形数据结构和布局算法。\n\n$ /Bioinfo/Pipeline/SoftWare/Python-3.7.3/bin/pip3 install pygraphviz\nCollecting pygraphviz\n Using cached https://files.pythonhosted.org/packages/7e/b1/d6d849ddaf6f11036f9980d433f383d4c13d1ebcfc3cd09bc845bda7e433/pygraphviz-1.5.zip\nInstalling collected packages: pygraphviz\n Running setup.py install for pygraphviz ... error\n Complete output from command /Bioinfo/Pipeline/SoftWare/Python-3.7.3/bin/python3.7 -u -c "import setuptools, tokenize;__file__=\'/tmp/pip-install-_zdjdg0j/pygraphviz/setup.py\';f=getattr(tokenize, \'open\', open)(__file__);code=f.read().replace(\'\\r\\n\', \'\\n\');f.close();exec(compile(code, __file__, \'exec\'))" install --record /tmp/pip-record-g0mz7lrq/install-record.txt --single-version-externally-managed --compile:\n running install\n Trying dpkg\n Failed to find dpkg\n Trying pkg-config\n Package libcgraph was not found in the pkg-config search path.\n Perhaps you should add the directory containing `libcgraph.pc\'\n to the PKG_CONFIG_PATH environment variable\n No package \'libcgraph\' found\n Traceback (most recent call last):\n File "", line 1, in \n File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup.py", line 93, in \n tests_require=[\'nose>=1.3.7\', \'doctest-ignore-unicode>=0.1.2\', \'mock>=2.0.0\'],\n File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/site-packages/setuptools/__init__.py", line 145, in setup\n return distutils.core.setup(**attrs)\n File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/distutils/core.py", line 148, in setup\n dist.run_commands()\n File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/distutils/dist.py", line 966, in run_commands\n self.run_command(cmd)\n File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/distutils/dist.py", line 985, in run_command\n cmd_obj.run()\n File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup_commands.py", line 44, in modified_run\n self.include_path, self.library_path = get_graphviz_dirs()\n File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup_extra.py", line 162, in get_graphviz_dirs\n include_dirs, library_dirs = _try_configure(include_dirs, library_dirs, _pkg_config)\n File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup_extra.py", line 117, in _try_configure\n i, l = try_function()\n File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup_extra.py", line 72, in _pkg_config\n output = S.check_output([\'pkg-config\', \'--libs-only-L\', \'libcgraph\'])\n File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/subprocess.py", line 395, in check_output\n **kwargs).stdout\n File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/subprocess.py", line 487, in run\n output=stdout, stderr=stderr)\n subprocess.CalledProcessError: Command \'[\'pkg-config\', \'--libs-only-L\', \'libcgraph\']\' returned non-zero exit status 1.\n\n ----------------------------------------\nCommand "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/bin/python3.7 -u -c "import setuptools, tokenize;__file__=\'/tmp/pip-install-_zdjdg0j/pygraphviz/setup.py\';f=getattr(tokenize, \'open\', open)(__file__);code=f.read().replace(\'\\r\\n\', \'\\n\');f.close();exec(compile(code, __file__, \'exec\'))" install --record /tmp/pip-record-g0mz7lrq/install-record.txt --single-version-externally-managed --compile" failed with error code 1 in /tmp/pip-install-_zdjdg0j/pygraphviz/\n\n参考:《Installation:fatal error: \'graphviz/cgraph.h\' file not found》\n$ wget https://graphviz.gitlab.io/pub/graphviz/stable/SOURCES/graphviz.tar.gz\n$ tar zvxf graphviz.tar.gz\n$ cd graphviz-2.40.1\n$ ./configure --prefix=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1\n$ make && make install\n推荐把安装好的 graphviz 添加到环境变量,这样可以避免运行过程中出现:"pygraphviz/graphviz_wrap.c:2987:29: fatal error: graphviz/cgraph.h: No such file or directory" 无法找到头文件的异常。\nexport PKG_CONFIG_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib/pkgconfig:$PKG_CONFIG_PATH\nexport LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib:$LD_LIBRARY_PATH\nexport C_INCLUDE_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/include:$C_INCLUDE_PATH\nexport CPLUS_INCLUDE_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/include:$CPLUS_INCLUDE_PATH\n如果 graphviz 添加到环境变量, pygraphviz\xa0的 python 包可以参考下面的方法安装:\n$ /Bioinfo/Pipeline/SoftWare/Python-3.7.3/bin/pip3 install --global-option=build_ext --global-option="-I/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/include" --global-option="-L/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib" pygraphviz\n/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/site-packages/pip/_internal/commands/install.py:207: UserWarning: Disabling all use of wheels due to the use of --build-options / --global-options / --install-options.\n cmdoptions.check_install_build_global(options)\nCollecting pygraphviz\n Using cached https://files.pythonhosted.org/packages/7e/b1/d6d849ddaf6f11036f9980d433f383d4c13d1ebcfc3cd09bc845bda7e433/pygraphviz-1.5.zip\nInstalling collected packages: pygraphviz\n Running setup.py install for pygraphviz ... done\nSuccessfully installed pygraphviz-1.5\n编译安装\n这里的编译安装,以 Python-3.11.6 为示例。\n第一,下载 Python 源码,解压。\n# 官网下载地址 https://www.python.org/downloads\nwget https://www.python.org/ftp/python/3.11.6/Python-3.11.6.tgz\n\n# 解压到指定目录\ntar zvxf Python-3.11.6.tgz -C /usr/local/src\n第二,进入解压的源码路径,编译 Python 源码。\n$ export PKG_CONFIG_PATH=/Bioinfo/Pipeline/SoftWare/libffi-3.2.1/lib/pkgconfig:$PKG_CONFIG_PATH\n$ export PKG_CONFIG_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib/pkgconfig:$PKG_CONFIG_PATH\n\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/libffi-3.2.1/lib64:$LD_LIBRARY_PATH\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib:$LD_LIBRARY_PATH\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1/lib:$LD_LIBRARY_PATH\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/lib:$LD_LIBRARY_PATH\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/gdbm-1.23/lib:$LD_LIBRARY_PATH\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/lib:$LD_LIBRARY_PATH\n\n$ export TCLTK_LIBS="-L/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/lib -ltcl8.6 -ltk8.6"\n$ export TCLTK_CFLAGS="-I/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/include"\n\n$ ./configure \\\n--enable-optimizations \\\n--prefix=/Bioinfo/Pipeline/SoftWare/Python-3.11.6 \\\n--with-openssl=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1 \\\n--with-openssl-rpath=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1/lib \\\nCC=/Bioinfo/Pipeline/SoftWare/gcc-7.3.0/bin/gcc \\\nCXX=/Bioinfo/Pipeline/SoftWare/gcc-7.3.0/bin/c++ \\\nLDFLAGS="-L/Bioinfo/Pipeline/SoftWare/libffi-3.2.1/lib64 \\\n -L/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib \\\n -L/RiboBio/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/lib \\\n -L/Bioinfo/Pipeline/SoftWare/gdbm-1.23/lib" \\\nCPPFLAGS="-I/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/include \\\n -I/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/include \\\n -I/Bioinfo/Pipeline/SoftWare/gdbm-1.23/include" \\\nPKG_CONFIG_PATH="/Bioinfo/Pipeline/SoftWare/libffi-3.2.1/lib/pkgconfig: \\\n /Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib/pkgconfig"\n\n--enable-optimizations\xa0 是优化选项(LTO,PGO\xa0 等)加上这个 \xa0flag\xa0 编译后,性能有 \xa010%\xa0 左右的优化,但是这会明显的增加编译时间。建议使用这个参数;\n--prefix\xa0 声明安装路径;\n安装多个 python 的版本,如果不开启--enable-shared,指定不同路径即可。当开启--enable-shared 时,默认只有一个版本的 python。\nPython 3 编译可以在 configure 或者环境变量中指定 OpenSSL 安装路径进行编译的方式解决 OpenSSL 依赖,否则 make\xa0 过程可能出错。\n\n$ make\n......\nThe following modules found by detect_modules() in setup.py, have been\nbuilt by the Makefile instead, as configured by the Setup files:\n_abc atexit pwd\ntime\n\n\nFailed to build these modules:\n_ctypes _hashlib _ssl\n\n\nCould not build the ssl module!\nPython requires an OpenSSL 1.0.2 or 1.1 compatible libssl with X509_VERIFY_PARAM_set1_host().\nLibreSSL 2.6.4 and earlier do not provide the necessary APIs, https://github.com/libressl-portable/portable/issues/381\n\n......\n\nmake\xa0过程如果出现 ModuleNotFoundError: No module named \'_ctypes\'\xa0或者 INFO: Could not locate ffi libs and/or headers\xa0参考:https://groups.google.com/forum/#!topic/comp.lang.python/npv-wzmytzo\n\n\n\n对于低版本的 Python 如果指定\xa0--with-openssl=DIR\xa0依然无法解决 ssl 模块的问题,可以参考修改 Modules/Setup.dist 文件(默认这块是注释的,放开注释即可。这块功能是开启 SSL 模块,不然会出现安装完毕后,提示找不到 ssl 模块的错误)再执行 configure,修改内容如下:\n\n# Socket module helper for SSL support; you must comment out the other\n# socket line above, and possibly edit the SSL variable:\nSSL=/usr/local/ssl\n_ssl _ssl.c \\\n -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \\\n -L$(SSL)/lib -lssl -lcrypto\n第三,Makefile 生后依次在当前路径执行编译和安装命令。\nmake && make install\n第四,安装完成。以上命令执行完毕,且无报错的情况下,我们将默认 python 换将切换至 3.11.6(一般不建议替换,个人建议把自定义安装的 Python bin 路径添加到 PATH 环境变量即可):\n# 替换系统自带的 python(不建议)\nmv /usr/bin/python /usr/bin/python2\nln -s /Bioinfo/Pipeline/SoftWare/Python-3.11.6/bin/python3 /usr/bin/python3\n\n# 添加新 Python 到 PATH 环境变量(建议)\necho "export PATH=/Bioinfo/Pipeline/SoftWare/Python-3.11.6/bin:$PATH" >>~/.bashrc\nsource ~/.bashrc\n运行命令 python -V\xa0,查看是否出现 3.11.6\xa0 的版本,出现即为安装成功。\n其他工具\nPython >= 3.10 在安装时候,默认会同时安装 pip3!如果你的 python < 3.10,可以参考下面的方法安装 pip。\n# 下载 setuptools 和 pip 安装程序\ncurl https://bootstrap.pypa.io/get-pip.py -o get-pip.py\npython3 get-pip.py\n至此,CentOS Linux release\xa06.5 下的 python-3.11.6\xa0 全部安装完成。如果在安装过程中出现其他的报错,建议把 error 关键信息直接复制到 Google 进行检索,参考其他人的解决方法。\n其他异常与解决\n_bz2\n\n系统:CentOS Linux release 7.7.1908 (Core)\nGCC:gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39)\n\n在 CentOS 7 中安装 Python-3.6.9 中发现 make 过程中一直提示:"ModuleNotFoundError: No module named \'_bz2\'",尽管 sudo yum install bzip2 bzip2-devel\xa0 已经安装了 bzip2 的依赖,问题还是不得其解。最后参考 stackoverflow 上的《Correctly building local python3, with bz2 support》,终于解决问题,下面记录一下。\nCorrectly building local python3, with bz2 support\n手动安装 bzip2:\nwget https://nchc.dl.sourceforge.net/project/bzip2/bzip2-1.0.6.tar.gz\ntar zvxf bzip2-1.0.6.tar.gz\ncd bzip2-1.0.6\nmake -f Makefile_libbz2_so # 这一步是生成 libbz2.so.1.0.6 的动态库文件\nmake\nmake install PREFIX=/usr/local/software/bzip2-1.0.6\ncp libbz2.so.1.0.6 /usr/local/software/bzip2-1.0.6/lib/\n几点说明:\n\nbzip2 的官网 \xa0http://www.bzip.org/\xa0 已经把 bzip2 的源码下载链接放到了 \xa0SourceForge,网络上一些从 \xa0http://www.bzip.org/1.0.6/bzip2-1.0.6.tar.gz\xa0 下载的做法已经失效。\nSourceForge 上 bzip2 的最新版本还是 1.0.6(Last modified 2018-11-3),更高级版本的 bzip2 我也不知道是否存在,也不知道能不能用。\n\n\n编译安装 Python-3.6.9:\n$ wget https://www.python.org/ftp/python/3.6.9/Python-3.6.9.tgz\n$ tar zvxf Python-3.6.9.tgz\n$ cd Python-3.6.9\n$ ./configure --enable-optimizations --prefix=/usr/local/software/python-3.6 CFLAGS="-I/usr/local/software/bzip2-1.0.6/include" LDFLAGS="-L/usr/local/software/bzip2-1.0.6/lib"\n$ make\n$ make install\n\nPython-3.6.9 中的 ./configure --help\xa0中没有 --with-openssl\xa0参数!有点神奇,我也不知道原因。\n安装完成可以用 from _bz2 import BZ2Compressor, BZ2Decompressor\xa0测试一下 _bz2\xa0 是否可用。\n\n参考资料\n\n行者无疆-ITer,《python2.7 源码编译安装》, 博客园\nScott Frazer,《How do I compile Python 3.4 with custom OpenSSL?》, Stack Overflow', 'bodyHTML': '

编程,作为生物信息学的一个基础性技能,是任何一个生信工程师都无法绕开话题。也许有些人还在纠结 Perl 和 Python 到底应该学习哪一个,但作为目前最火最流行的编程语言 Python 还是非常值得尝试的。它不但可以进行文本处理,在统计、网站、游戏、爬虫、数据可视化等方面也有非常强大的应用,比起曾经的 Perl 真的强大和全面很多,且比 Perl 更容易入手。不管从长远发展,还是短期需要,学会 Python,看懂 Perl (或者先学 \xa0 Python,后学 Perl) 应该是每一个生信工程必备的基础技能之一。

\n

工欲善其事,必先利其器。关于 Python 安装教程在网上一搜一大把,但总感觉不够全面,尤其对于中间出现的一些问题的解决方法不尽如人意。鉴于此,本文基于 \xa0CentOS/RHEL Linux 对 Python 的源码编译安装进行了一下简单的总结,记录如下。

\n

安装环境

\n

Red Hat 6.5 + GCC 4.4.7(GCC-7.3.0 - 此版本 gcc 为手动安装)。

\n

GCC 高级版本手动或者 yum 安装参考以下文章:

\n\n
$ lsb_release -a\nLSB Version:    :base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noarch:graphics-4.0-amd64:graphics-4.0-noarch:printing-4.0-amd64:printing-4.0-noarch\nDistributor ID: RedHatEnterpriseServer\nDescription:    Red Hat Enterprise Linux Server release 6.5 (Santiago)\nRelease:        6.5\nCodename:       Santiago\n\n$ gcc --version\ngcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-4)\nCopyright (C) 2010 Free Software Foundation, Inc.\nThis is free software; see the source for copying conditions.  There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
\n

解决依赖

\n

如果您拥有 root 权限,请执以下依赖安装:

\n
yum install zlib\nyum install zlib-devel\nyum install openssl\nyum install openssl-devel\nyum install libffi\nyum install libffi-devel\nyum install readline readline-devel sqlite sqlite-devel tk-devel
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
缺少库名称安装命令
_uuidyum install libuuid-devel
readlineyum install readline-devel
_tkinteryum install tk-devel
_ffiyum install libffi-devel
_cursesyum install ncurses-libs
_sqliteyum install sqlite-devel
_bz2yum isntall bzip2-devel
_sslyum install openssl-devel
_gdbmyum install gdbm-devel
_dbiyum install libdbi-devel
_zlibyum install zlib-devel
lzmayum install xz-develyum install python-backports-lzma
\n

如果您没有 root 权限,可以参考《手把手教你在 Linux 源码安装最新版本的 R》一文,手动一个个去解决以上的依赖。

\n

_sqlite3

\n

执行 make 过程中提示 _sqlite3 not found,如下:

\n
$ make\n......\nPython build finished successfully!\nThe necessary bits to build these optional modules were not found:\n_sqlite3              _ssl\nTo find the necessary bits, look in setup.py in detect_modules() for the module\'s name.\n\nThe following modules found by detect_modules() in setup.py, have been\nbuilt by the Makefile instead, as configured by the Setup files:\n_abc                  atexit                pwd\ntime
\n

系统已安装 sqlite3

\n

如果执行 rpm -qa|grep sqlite 看到 sqlite 和 sqlite-devel 都已经安装(libsqlite3.so 默认保存在 /usr/lib64 下; sqlite3.h 默认保存在 /usr/include 下)。

\n
$ sqlite3 -version\n3.6.20\n\n$ ll /usr/lib64/libsqlite3.so\nlrwxrwxrwx 1 root root 19 Apr 23  2015 /usr/lib64/libsqlite3.so -> libsqlite3.so.0.8.6\n\n$ ll /usr/include/sqlite3.h\n-rw-r--r-- 1 root root 263K Nov 25  2009 /usr/include/sqlite3.h
\n

但是,执行 make 依然出现以上报错,参考下面的方法《python build from source: cannot build optional module sqlite3 - Stack Overflow》。

\n

手动安装 sqlite3

\n
$ wget https://www.sqlite.org/2021/sqlite-autoconf-3360000.tar.gz --no-check-certificate\n$ tar zvxf sqlite-autoconf-3360000.tar.gz\n$ cd sqlite-autoconf-3360000\n$ ./configure --prefix=/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0\n$ make\n$ make install
\n

配置 sqlite3

\n
    \n
  1. 配置环境
  2. \n
\n
$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/lib:$LD_LIBRARY_PATH
\n
    \n
  1. 调整源码或编译
  2. \n
\n

对于 3.11.x 以上版本的 Python 可以在 configure 指定自定义安装的 sqlite3 路径解决 _sqlite3 依赖。

\n
./configure ... \\\n    LDFLAGS="-L/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/lib" \\\n    CPPFLAGS="-I/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/include" \n
\n

有些低版本的 Python (如 3.7) 可能需要再源码文件中加入 sqlite3.h 的文件路径。

\n
    \n
  1. 找到 sqlite3.h 文件的保存目录。
  2. \n
  3. 修改 setup.py 文件,在 sqlite_inc_paths 中加上 sqlite3.h 的文件路径。
  4. \n
\n
sqlite_inc_paths = [ \'/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/include\',\n                     \'/usr/include\',\n                     \'/usr/include/sqlite\',\n                     \'/usr/include/sqlite3\',\n                     \'/usr/local/include\',\n                     \'/usr/local/include/sqlite\',\n                     \'/usr/local/include/sqlite3\',\n                   ]
\n

_ssl

\n

Python3 需要引用 openssl\xa0 模块,但是 python3.7+ 在 CentOS 中要求的 openssl 版本最低为 1.0.2,而 CentOS 默认的为 1.0.1(CentOS-6.x 通过 yum\xa0 源安装的 openssl 的最高版本是 1.0.1),所以需要手动更新 openssl。

\n

对于 openssl 版本的选择,建议至少选择 1.1.1+ 版本:

\n
    \n
  1. urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the \'ssl\' module is compiled with \'OpenSSL 1.0.2k-fips 26 Jan 2017\'. See: urllib3/urllib3#2168
  2. \n
  3. Python requires an OpenSSL 1.0.2 or 1.1 compatible libssl with X509_VERIFY_PARAM_set1_host().
  4. \n
\n
# 下载\nwget http://www.openssl.org/source/openssl-1.1.1.tar.gz\n\n# 解压缩\ntar -zxvf openssl-1.1.1.tar.gz\n\n# 进入目录安装\ncd openssl-1.1.1\n\n# 进行配置下,自定义\n./config --prefix=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1 shared zlib\n\n# 编译并安装\nmake && make install\n\n# 配置到用户环境变量,随处使用\necho "export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1/lib:$LD_LIBRARY_PATH" >> $HOME/.bashrc\n\n# 是环境变量配置生效\nsource $HOME/.bashrc
\n

请注意:

\n
    \n
  1. openssl\xa0编译(config)的时候 必须要加上 shared\xa0 参数,否者源码安装 Python 即使添加了 --with-openssl\xa0的自定义路径,依然会导致 Could not build the ssl module!\xa0报错!
  2. \n
  3. https://www.openssl.org/source/\xa0下载的源码 openssl-1.0.2s、openssl-1.0.2m,包括 \xa0CentOS-7.5 使用 yum\xa0安装的最高版本的 openssl-1.0.2k 目前发现依然会导致 Could not build the ssl module\xa0,建议从 https://www.openssl.org/source/old/\xa0下载 1.1.1 的源码编译安装。
  4. \n
\n

最后,在 Python 执行 configure 的时候指定 openssl 的相关参数:

\n
./configure ... \\\n    --with-openssl=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1 \\\n    --with-openssl-rpath=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1/lib \\\n
\n

_tkinter

\n

Tkinter 模块缺失是一个比较棘手的问题,为此专门写了一篇文章来介绍这个问题。

\n

具体请参考:Python 中 tkinter 源码安装使用与中文乱码 - Knowledge-Garden#12

\n

_dbm

\n

_dbm_gdbm 的模块缺失可以通过下面手动的方法解决。

\n
wget https://ftp.gnu.org/gnu/gdbm/gdbm-1.23.tar.gz\ntar -zxvf gdbm-1.23.tar.gz\n./configure --prefix=/Bioinfo/Pipeline/SoftWare/gdbm-1.23 --enable-libgdbm-compat  --enable-debug\nmake && make install\n
\n

最后,增加环境变量,并调整 Python 执行 configure 时的参数:

\n
export PATH=/Bioinfo/Pipeline/SoftWare/gdbm-1.23/bin:$PATH\nexport LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/gdbm-1.23/lib:$LD_LIBRARY_PATH\n\n./configure ... \\\n    LDFLAGS="-L/Bioinfo/Pipeline/SoftWare/gdbm-1.23/lib" \\\n    CPPFLAGS="-I/Bioinfo/Pipeline/SoftWare/gdbm-1.23/include"\n
\n

_lzma

\n

正常情况下,下面的方法可以解决该问题(如果您有 root 权限的话)。

\n
# For ubuntu:\n$ sudo apt-get install liblzma-dev\n\n# For centos:\n$ yum install xz-devel
\n

普通用户可以手动安装解决:

\n
$ wget https://tukaani.org/xz/xz-5.2.5.tar.gz --no-check-certificat\n$ tar zvxf xz-5.2.5.tar.gz\n$ cd xz-5.2.5\n$ ./configure --prefix=/Bioinfo/Pipeline/SoftWare/xz-5.2.5\n$ make\n$ make install
\n

最后,配置环境:

\n
$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/xz-5.2.5/lib:$LD_LIBRARY_PATH
\n

_ctypes

\n

在 CentOS 6.x 安装 libffi-devel\xa0 的时候出现以下问题:

\n
$ yum install libffi-devel\nLoaded plugins: product-id, refresh-packagekit, search-disabled-repos, security, subscription-manager\nThis system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.\nSetting up Install Process\ncdrom                                                                                                                                         | 4.1 kB     00:00 ...\nNo package libffi-devel available.\nError: Nothing to do
\n

可以使用下面的方法安装:

\n
[root@log01 ~]# rpm -ivh http://mirror.centos.org/centos/6/os/x86_64/Packages/libffi-devel-3.0.5-3.2.el6.x86_64.rpm\nRetrieving http://mirror.centos.org/centos/6/os/x86_64/Packages/libffi-devel-3.0.5-3.2.el6.x86_64.rpm\nwarning: /var/tmp/rpm-tmp.V9ihbu: Header V3 RSA/SHA256 Signature, key ID c105b9de: NOKEY\nPreparing...                ########################################### [100%]\n   1:libffi-devel           ########################################### [100%]\n[root@log01 ~]# rpm -qa|grep libffi\nlibffi-3.0.5-3.2.el6.x86_64\nlibffi-devel-3.0.5-3.2.el6.x86_64
\n

手动的源码方法安装如下:

\n
$ wget ftp://sourceware.org/pub/libffi/libffi-3.2.1.tar.gz\n$ tar zvxf libffi-3.2.1.tar.gz\n$ ./configure --prefix=/Bioinfo/Pipeline/SoftWare/libffi-3.2.1\n$ make\n$ make install
\n

pygraphviz

\n

如果你不需要使用 pygraphviz,可以不用管这个依赖。

\n
\n

PyGraphviz is a Python interface to the Graphviz graph layout and visualization package. With PyGraphviz you can create, edit, read, write, and draw graphs using Python to access the Graphviz graph data structure and layout algorithms.

\n
\n
\n

PyGraphviz 是 Graphviz 图形布局和可视化包的 Python 接口。 借助 PyGraphviz,您可以使用 Python 创建、编辑、读取、写入和绘制图形,以访问 Graphviz 图形数据结构和布局算法。

\n
\n
$ /Bioinfo/Pipeline/SoftWare/Python-3.7.3/bin/pip3 install pygraphviz\nCollecting pygraphviz\n  Using cached https://files.pythonhosted.org/packages/7e/b1/d6d849ddaf6f11036f9980d433f383d4c13d1ebcfc3cd09bc845bda7e433/pygraphviz-1.5.zip\nInstalling collected packages: pygraphviz\n  Running setup.py install for pygraphviz ... error\n    Complete output from command /Bioinfo/Pipeline/SoftWare/Python-3.7.3/bin/python3.7 -u -c "import setuptools, tokenize;__file__=\'/tmp/pip-install-_zdjdg0j/pygraphviz/setup.py\';f=getattr(tokenize, \'open\', open)(__file__);code=f.read().replace(\'\\r\\n\', \'\\n\');f.close();exec(compile(code, __file__, \'exec\'))" install --record /tmp/pip-record-g0mz7lrq/install-record.txt --single-version-externally-managed --compile:\n    running install\n    Trying dpkg\n    Failed to find dpkg\n    Trying pkg-config\n    Package libcgraph was not found in the pkg-config search path.\n    Perhaps you should add the directory containing `libcgraph.pc\'\n    to the PKG_CONFIG_PATH environment variable\n    No package \'libcgraph\' found\n    Traceback (most recent call last):\n      File "<string>", line 1, in <module>\n      File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup.py", line 93, in <module>\n        tests_require=[\'nose>=1.3.7\', \'doctest-ignore-unicode>=0.1.2\', \'mock>=2.0.0\'],\n      File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/site-packages/setuptools/__init__.py", line 145, in setup\n        return distutils.core.setup(**attrs)\n      File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/distutils/core.py", line 148, in setup\n        dist.run_commands()\n      File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/distutils/dist.py", line 966, in run_commands\n        self.run_command(cmd)\n      File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/distutils/dist.py", line 985, in run_command\n        cmd_obj.run()\n      File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup_commands.py", line 44, in modified_run\n        self.include_path, self.library_path = get_graphviz_dirs()\n      File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup_extra.py", line 162, in get_graphviz_dirs\n        include_dirs, library_dirs = _try_configure(include_dirs, library_dirs, _pkg_config)\n      File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup_extra.py", line 117, in _try_configure\n        i, l = try_function()\n      File "/tmp/pip-install-_zdjdg0j/pygraphviz/setup_extra.py", line 72, in _pkg_config\n        output = S.check_output([\'pkg-config\', \'--libs-only-L\', \'libcgraph\'])\n      File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/subprocess.py", line 395, in check_output\n        **kwargs).stdout\n      File "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/subprocess.py", line 487, in run\n        output=stdout, stderr=stderr)\n    subprocess.CalledProcessError: Command \'[\'pkg-config\', \'--libs-only-L\', \'libcgraph\']\' returned non-zero exit status 1.\n\n    ----------------------------------------\nCommand "/Bioinfo/Pipeline/SoftWare/Python-3.7.3/bin/python3.7 -u -c "import setuptools, tokenize;__file__=\'/tmp/pip-install-_zdjdg0j/pygraphviz/setup.py\';f=getattr(tokenize, \'open\', open)(__file__);code=f.read().replace(\'\\r\\n\', \'\\n\');f.close();exec(compile(code, __file__, \'exec\'))" install --record /tmp/pip-record-g0mz7lrq/install-record.txt --single-version-externally-managed --compile" failed with error code 1 in /tmp/pip-install-_zdjdg0j/pygraphviz/\n
\n

参考:《Installation:fatal error: \'graphviz/cgraph.h\' file not found

\n
$ wget https://graphviz.gitlab.io/pub/graphviz/stable/SOURCES/graphviz.tar.gz\n$ tar zvxf graphviz.tar.gz\n$ cd graphviz-2.40.1\n$ ./configure --prefix=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1\n$ make && make install
\n

推荐把安装好的 graphviz 添加到环境变量,这样可以避免运行过程中出现:"pygraphviz/graphviz_wrap.c:2987:29: fatal error: graphviz/cgraph.h: No such file or directory" 无法找到头文件的异常。

\n
export PKG_CONFIG_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib/pkgconfig:$PKG_CONFIG_PATH\nexport LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib:$LD_LIBRARY_PATH\nexport C_INCLUDE_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/include:$C_INCLUDE_PATH\nexport CPLUS_INCLUDE_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/include:$CPLUS_INCLUDE_PATH
\n

如果 graphviz 添加到环境变量, pygraphviz\xa0的 python 包可以参考下面的方法安装:

\n
$ /Bioinfo/Pipeline/SoftWare/Python-3.7.3/bin/pip3 install --global-option=build_ext --global-option="-I/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/include" --global-option="-L/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib" pygraphviz\n/Bioinfo/Pipeline/SoftWare/Python-3.7.3/lib/python3.7/site-packages/pip/_internal/commands/install.py:207: UserWarning: Disabling all use of wheels due to the use of --build-options / --global-options / --install-options.\n  cmdoptions.check_install_build_global(options)\nCollecting pygraphviz\n  Using cached https://files.pythonhosted.org/packages/7e/b1/d6d849ddaf6f11036f9980d433f383d4c13d1ebcfc3cd09bc845bda7e433/pygraphviz-1.5.zip\nInstalling collected packages: pygraphviz\n  Running setup.py install for pygraphviz ... done\nSuccessfully installed pygraphviz-1.5
\n

编译安装

\n

这里的编译安装,以 Python-3.11.6 为示例。

\n

第一,下载 Python 源码,解压。

\n
# 官网下载地址 https://www.python.org/downloads\nwget https://www.python.org/ftp/python/3.11.6/Python-3.11.6.tgz\n\n# 解压到指定目录\ntar zvxf Python-3.11.6.tgz -C /usr/local/src
\n

第二,进入解压的源码路径,编译 Python 源码。

\n
$ export PKG_CONFIG_PATH=/Bioinfo/Pipeline/SoftWare/libffi-3.2.1/lib/pkgconfig:$PKG_CONFIG_PATH\n$ export PKG_CONFIG_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib/pkgconfig:$PKG_CONFIG_PATH\n\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/libffi-3.2.1/lib64:$LD_LIBRARY_PATH\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib:$LD_LIBRARY_PATH\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1/lib:$LD_LIBRARY_PATH\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/lib:$LD_LIBRARY_PATH\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/gdbm-1.23/lib:$LD_LIBRARY_PATH\n$ export LD_LIBRARY_PATH=/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/lib:$LD_LIBRARY_PATH\n\n$ export TCLTK_LIBS="-L/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/lib -ltcl8.6 -ltk8.6"\n$ export TCLTK_CFLAGS="-I/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/include"\n\n$ ./configure \\\n--enable-optimizations \\\n--prefix=/Bioinfo/Pipeline/SoftWare/Python-3.11.6 \\\n--with-openssl=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1 \\\n--with-openssl-rpath=/Bioinfo/Pipeline/SoftWare/openssl-1.1.1/lib \\\nCC=/Bioinfo/Pipeline/SoftWare/gcc-7.3.0/bin/gcc \\\nCXX=/Bioinfo/Pipeline/SoftWare/gcc-7.3.0/bin/c++ \\\nLDFLAGS="-L/Bioinfo/Pipeline/SoftWare/libffi-3.2.1/lib64 \\\n         -L/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib \\\n         -L/RiboBio/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/lib \\\n         -L/Bioinfo/Pipeline/SoftWare/gdbm-1.23/lib" \\\nCPPFLAGS="-I/Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/include \\\n          -I/Bioinfo/Pipeline/SoftWare/sqlite-3.36.0/include \\\n          -I/Bioinfo/Pipeline/SoftWare/gdbm-1.23/include" \\\nPKG_CONFIG_PATH="/Bioinfo/Pipeline/SoftWare/libffi-3.2.1/lib/pkgconfig: \\\n                 /Bioinfo/Pipeline/SoftWare/graphviz-2.40.1/lib/pkgconfig"
\n
    \n
  • --enable-optimizations\xa0 是优化选项(LTO,PGO\xa0 等)加上这个 \xa0flag\xa0 编译后,性能有 \xa010%\xa0 左右的优化,但是这会明显的增加编译时间。建议使用这个参数;
  • \n
  • --prefix\xa0 声明安装路径;
  • \n
  • 安装多个 python 的版本,如果不开启--enable-shared,指定不同路径即可。当开启--enable-shared 时,默认只有一个版本的 python。
  • \n
  • Python 3 编译可以在 configure 或者环境变量中指定 OpenSSL 安装路径进行编译的方式解决 OpenSSL 依赖,否则 make\xa0 过程可能出错。
  • \n
\n
$ make\n......\nThe following modules found by detect_modules() in setup.py, have been\nbuilt by the Makefile instead, as configured by the Setup files:\n_abc                  atexit                pwd\ntime\n\n\nFailed to build these modules:\n_ctypes               _hashlib              _ssl\n\n\nCould not build the ssl module!\nPython requires an OpenSSL 1.0.2 or 1.1 compatible libssl with X509_VERIFY_PARAM_set1_host().\nLibreSSL 2.6.4 and earlier do not provide the necessary APIs, https://github.com/libressl-portable/portable/issues/381\n\n......
\n\n

image.png

\n
    \n
  • 对于低版本的 Python 如果指定\xa0--with-openssl=DIR\xa0依然无法解决 ssl 模块的问题,可以参考修改 Modules/Setup.dist 文件(默认这块是注释的,放开注释即可。这块功能是开启 SSL 模块,不然会出现安装完毕后,提示找不到 ssl 模块的错误)再执行 configure,修改内容如下:
  • \n
\n
# Socket module helper for SSL support; you must comment out the other\n# socket line above, and possibly edit the SSL variable:\nSSL=/usr/local/ssl\n_ssl _ssl.c \\\n    -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \\\n    -L$(SSL)/lib -lssl -lcrypto
\n

第三,Makefile 生后依次在当前路径执行编译和安装命令。

\n
make && make install
\n

第四,安装完成。以上命令执行完毕,且无报错的情况下,我们将默认 python 换将切换至 3.11.6(一般不建议替换,个人建议把自定义安装的 Python bin 路径添加到 PATH 环境变量即可):

\n
# 替换系统自带的 python(不建议)\nmv /usr/bin/python /usr/bin/python2\nln -s /Bioinfo/Pipeline/SoftWare/Python-3.11.6/bin/python3 /usr/bin/python3\n\n# 添加新 Python 到 PATH 环境变量(建议)\necho "export PATH=/Bioinfo/Pipeline/SoftWare/Python-3.11.6/bin:$PATH" >>~/.bashrc\nsource ~/.bashrc
\n

运行命令 python -V\xa0,查看是否出现 3.11.6\xa0 的版本,出现即为安装成功。

\n

其他工具

\n

Python >= 3.10 在安装时候,默认会同时安装 pip3!如果你的 python < 3.10,可以参考下面的方法安装 pip。

\n
# 下载 setuptools 和 pip 安装程序\ncurl https://bootstrap.pypa.io/get-pip.py -o get-pip.py\npython3 get-pip.py
\n

至此,CentOS Linux release\xa06.5 下的 python-3.11.6\xa0 全部安装完成。如果在安装过程中出现其他的报错,建议把 error 关键信息直接复制到 Google 进行检索,参考其他人的解决方法。

\n

其他异常与解决

\n

_bz2

\n
    \n
  • 系统:CentOS Linux release 7.7.1908 (Core)
  • \n
  • GCC:gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39)
  • \n
\n

在 CentOS 7 中安装 Python-3.6.9 中发现 make 过程中一直提示:"ModuleNotFoundError: No module named \'_bz2\'",尽管 sudo yum install bzip2 bzip2-devel\xa0 已经安装了 bzip2 的依赖,问题还是不得其解。最后参考 stackoverflow 上的《Correctly building local python3, with bz2 support》,终于解决问题,下面记录一下。
\nCorrectly building local python3, with bz2 support

\n

手动安装 bzip2:

\n
wget https://nchc.dl.sourceforge.net/project/bzip2/bzip2-1.0.6.tar.gz\ntar zvxf bzip2-1.0.6.tar.gz\ncd bzip2-1.0.6\nmake -f Makefile_libbz2_so  # 这一步是生成 libbz2.so.1.0.6 的动态库文件\nmake\nmake install PREFIX=/usr/local/software/bzip2-1.0.6\ncp libbz2.so.1.0.6 /usr/local/software/bzip2-1.0.6/lib/
\n

几点说明:

\n
    \n
  • bzip2 的官网 \xa0http://www.bzip.org/\xa0 已经把 bzip2 的源码下载链接放到了 \xa0SourceForge,网络上一些从 \xa0http://www.bzip.org/1.0.6/bzip2-1.0.6.tar.gz\xa0 下载的做法已经失效。
  • \n
  • SourceForge 上 bzip2 的最新版本还是 1.0.6(Last modified 2018-11-3),更高级版本的 bzip2 我也不知道是否存在,也不知道能不能用。
  • \n
\n

image.png

\n

编译安装 Python-3.6.9:

\n
$ wget https://www.python.org/ftp/python/3.6.9/Python-3.6.9.tgz\n$ tar zvxf Python-3.6.9.tgz\n$ cd Python-3.6.9\n$ ./configure --enable-optimizations --prefix=/usr/local/software/python-3.6 CFLAGS="-I/usr/local/software/bzip2-1.0.6/include" LDFLAGS="-L/usr/local/software/bzip2-1.0.6/lib"\n$ make\n$ make install
\n
    \n
  • Python-3.6.9 中的 ./configure --help\xa0中没有 --with-openssl\xa0参数!有点神奇,我也不知道原因。
  • \n
  • 安装完成可以用 from _bz2 import BZ2Compressor, BZ2Decompressor\xa0测试一下 _bz2\xa0 是否可用。
  • \n
\n

参考资料

\n
    \n
  1. 行者无疆-ITer,《python2.7 源码编译安装》, 博客园
  2. \n
  3. Scott Frazer,《How do I compile Python 3.4 with custom OpenSSL?》, Stack Overflow
  4. \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '1.3.5-Python'}]}, 'comments': {'nodes': []}}, {'title': 'Python 中 tkinter 源码安装使用与中文乱码', 'number': 12, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/12', 'createdAt': '2023-11-02T02:24:22Z', 'lastEditedAt': '2024-10-15T02:30:26Z', 'updatedAt': '2024-10-15T02:30:26Z', 'body': '主要是因为下面这两个原因,所以决定从源码编译安装去折腾一下 tkinter,以下是一些记录。\r\n\r\n## _tkinter not found\r\n\r\nPython 3 源码编译安装,执行 `make` 过程中提示 `_tkinter not found`,如下:\r\n```bash\r\n$ make\r\n......\r\nPython build finished successfully!\r\nThe necessary bits to build these optional modules were not found:\r\n_tkinter \r\n```\r\n\r\n## 中文乱码\r\n\r\n使用 Anaconda 3(conda 4.5.11)的 tkinter python 包(conda install -c conda-forge tk)开发 GUI 界面程序过程中,发现 UI 界面出现的中文 Unicode 乱码一直没办法解决。\r\n\r\n```python\r\n#-*- coding: utf-8 -*-\r\n\r\nimport sys\r\n\r\nfrom tkinter import *\r\ntop=Tk()\r\ntop.wm_title("菜单")\r\ntop.geometry("800x600+300+100") # 创建一个菜单项,类似于导航栏\r\nmenubar=Menu(top) # 创建菜单项\r\nfmenu1=Menu(top)\r\n# 如果该菜单时顶层菜单的一个菜单项,则它添加的是下拉菜单的菜单\r\nfor item in [\'新建文件\', \'打开文件\',\'结果保存\']:\r\n fmenu1.add_command(label=item)\r\n\r\nfmenu2=Menu(top)\r\nfor item in [\'程序设置\',\'程序运行\']:\r\n fmenu2.add_command(label=item)\r\n\r\nfmenu3=Menu(top)\r\nfor item in [\'使用教程\', \'版权信息\', \'检查更新\']:\r\n fmenu3.add_command(label=item)\r\n\r\n# add_cascade 的一个很重要的属性就是 menu 属性,它指明了要把那个菜单级联到该菜单项上\r\n# 当然,还必不可少的就是 label 属性,用于指定该菜单项的名称\r\nmenubar.add_cascade(label=\'文件\', menu=fmenu1)\r\nmenubar.add_cascade(label="程序", menu=fmenu2)\r\nmenubar.add_cascade(label="帮助", menu=fmenu3)\r\n\r\n# 最后可以用窗口的 menu 属性指定我们使用哪一个作为它的顶层菜单\r\ntop[\'menu\']=menubar\r\ntop.mainloop()\r\n```\r\n\r\n![](https://shub.weiyan.tech/yuque/elog-cookbook-img/Fh22i487OzvY-uSXvAuFs6rEXXvu.png)\r\n\r\n我们也可以确认一下是不是 Tk 本身的问题:\r\n```\r\necho \'pack [button .h -text "Hello, World! 显示中文" -command exit]\' | wish\r\n```\r\n- 正常显示\r\n ![TK 正常显示](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/tk-ok.png)\r\n\r\n- 中文乱码\r\n ![TK 中文乱码](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/tk-error.png)\r\n\r\n**一些参考资料:**\r\n\r\n- Python 3.x 中文编码转换的问题:\r\n- Python 2.6 Tk 中文乱码解決方法:\r\n- tkinter 乱码,pyqt4 乱码:\r\n\r\n上面几种方法测试后,问题依然存在。在 google 上一番搜索和来回测试之后,发现了几点信息:\r\n\r\n- 有人说,可能是 tcl/tk 安装不完整造成的。\r\n- tcl/tk 重装后需要对 Python 重新编译 tkinter 才能起作用。\r\n- conda install -c conda-forge tk,虽然没有任何报错,python2 中 import tkinter 也正常,但 conda 的软件安装就像一个黑盒子,无法确认 tcl/tk 是否完整安装。\r\n- python 的 PyPI 仓库中是没有 tkinter 包的,想要使用 `pip install tkinter` 卸载或者重装都是行不通的。\r\n- 网上也有人说可以使用 `yum install python3-tk/python-tk` 解决,但对于本人来说,没用。\r\n\r\n## 什么是 tcl, tk, tkinter\r\n\r\n> The\xa0[tkinter](https://docs.python.org/3.6/library/tkinter.html#module-tkinter)\xa0package (“Tk interface”) is the standard Python interface to the Tk GUI toolkit. Both Tk and\xa0[tkinter](https://docs.python.org/3.6/library/tkinter.html#module-tkinter)\xa0are available on most Unix platforms, as well as on Windows systems. (Tk itself is not part of Python; it is maintained at ActiveState.)\r\n>\r\n> Running\xa0`python\xa0-m\xa0tkinter`\xa0from the command line should open a window demonstrating a simple Tk interface, letting you know that\xa0[tkinter](https://docs.python.org/3.6/library/tkinter.html#module-tkinter)\xa0is properly installed on your system, and also showing what version of Tcl/Tk is installed, so you can read the Tcl/Tk documentation specific to that version.\r\n>\r\n> From \r\n\r\nTcl 是"工具控制语言(Tool Control Language)"的缩写。Tk 是 Tcl "图形工具箱" 的扩展,它提供各种标准的 GUI 接口项,以利于迅速进行高级应用程序开发。\r\n\r\ntkinter 包("Tk 接口")是 Tk GUI 工具包的标准 Python 接口。 Tk 和 \xa0tkinter 在大多数 Unix 平台以及 Windows 系统上都可用(Tk 本身不是 Python 的一部分,它在 ActiveState 中维护)。您可以通过从命令行运行 \xa0`python -m\xa0tkinter`来检查 \xa0tkinter 是否已正确安装在系统上。如果已经安装该命令会打开一个简单的 Tk 界面,该界面除了让我们知道 tkinter 已正确安装,并且还显示安装了哪个版本的 Tcl/Tk,因此我们可以阅读特定于该版本的 Tcl/Tk 文档。\r\n\r\n![](https://shub.weiyan.tech/yuque/elog-cookbook-img/FpWx6rSTKaQ1BXXPQJzchNbviKYd.png)\r\n\r\n如果 \xa0tkinter\xa0 没有安装,则会提示找不到该包(注意在 Python 2 中该包包名为 Tkinter,Python 3 中为 tkinter):\r\n\r\n![](https://shub.weiyan.tech/yuque/elog-cookbook-img/FrRwzLFA1tIq2VfwS4p7i0dVLTjP.png)\r\n\r\n接下来我们将尝试在 Python 2/3 中安装 Tcl/Tk,并重新编译 Python 2/3,已完成 Tkinter 安装(tkinter 为 Python 的标准库,标准库的安装需要重新编译 Python ?)。\r\n\r\n## ActiveTcl 安装\r\n\r\nActiveTcl 是 ActiveState 发布的关于 Tcl/Tk 的发行版本,该发行版本包含了最新版本的 Tk 和 Tcl 程序,我们下载其免费的社区版本进行安装即可。\r\n\r\n参考下载链接:\r\n参考安装教程:\r\n\r\n以下为 CentOS 6.5 下 **ActiveTcl-8.6.9** 的一些安装记录,仅作参考。\r\n\r\n```bash\r\n$ curl -fL "https://shenweiyan-generic.pkg.coding.net/btscl/activetcl/ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d.tar.gz?version=8.6.9.8609.2" -o ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d.tar.gz\r\n$ tar zvxf ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d.tar.gz\r\n$ cd ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d\r\n$ ./install.sh\r\n......\r\nCancel [no] => [RET]\r\nAccept License [yes] => \'A\' >>A\r\n\r\nPlease specify the installation directory.\r\nPath [/opt/ActiveTcl-8.6]: /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9\r\n\r\nPlease specify the directory for the demos.\r\nPath [/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/demos]:\r\n\r\nPlease specify the runtime installation directory.\r\n\r\nThis is the directory the applications will see as their installation directory\r\nwhen searching for packages and libraries, instead of the directory the files\r\nwere copied to. In most circumstances this is the same as the installation\r\ndirectory chosen before.\r\nPath [/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9]:\r\n\r\nPress return to begin installation\r\n Installation Directory: /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9\r\n Demos Directory: /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/demos\r\n Runtime Directory: See Installation Directory\r\nCancel => C\r\nNext => [RET] >>\r\n\r\nInstalling ActiveTcl ...\r\n Creating directory /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/share ...\r\n Creating directory /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/share/man ...\r\n ......\r\n\r\nPlease do not forget to extend your PATH and MANPATH variables to\r\nget access to the applications and manpages distributed with ActiveTcl.\r\n\r\nFor a csh or compatible perform\r\n setenv PATH "/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/bin:$PATH"\r\n\r\nFor a sh or similar perform\r\n PATH="/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/bin:$PATH"\r\n export PATH\r\n\r\nSome shells (bash for example) allow\r\n export PATH="/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/bin:$PATH"\r\n\r\nSimilar changes are required for MANPATH\r\nFinish >>\r\n```\r\n\r\nActiveTcl 安装完成后,需要把 path 添加至环境变量(\\~/.bashrc):\r\n```\r\nexport PATH="/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/bin:$PATH"\r\n```\r\n\r\n## Tcl/Tk\r\n\r\n我们也可以直接去 直接通过源码的方式去编译安装 Tcl/Tk,尤其是当你的系统版本比较低,需要低版本的 Tcl/Tk,这种方法会比较合适。\r\n\r\n以 tcl8.5.19-src.tar.gz/tk8.5.19-src.tar.gz 为例,下载完成后,直接解压,然后执行常规安装即可。\r\n```\r\ncd tcl8.5.19/unix\r\n./configure\r\nmake\r\nmake test\r\nmake install\r\n```\r\n\r\n## Python 重新编译安装\r\n\r\n参考:[What’s New In Python 3.11](https://docs.python.org/3/whatsnew/3.11.html) - doc.python.org\r\n\r\n> 📢 **注意:**\r\n>\r\n> 1. Python 3.11.x 起(如 Python-3.11.3)中的 `configure` 已经把 `--with-tcltk-includes`和`--with-tcltk-libs`这两个参数移除!并使用 `TCLTK_CFLAGS` 和 `TCLTK_LIBS` 替代!!!\r\n> 2. Python 3.10.x (及以下版本,如 Python-3.9.16) 以及 Python 2.x.x 在 `configure` 中 `--with-tcltk-includes`和`--with-tcltk-libs`都是有的,通过这两个参数可以解决 Tkinter 的问题!!!\r\n\r\n### Python 3\r\n\r\n这里以 Python-3.11.6 为例,参考 [Python 3.11.0 install doesn’t recognize homebrew Tcl/Tk due to --with-tcltk-libs, --with-tcltk-includes switches being removed from 3.11 - pyenv#2499](https://github.com/pyenv/pyenv/issues/2499),在编译安装过程中使用 `TCLTK_CFLAGS` 和 `TCLTK_LIBS` 解决 `_tkinter` 缺失的问题。\r\n```\r\nexport TCLTK_LIBS="-L/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/lib -ltcl8.6 -ltk8.6" # 8.5.x 版本,需改为 -ltcl8.5 -ltk8.5\r\nexport TCLTK_CFLAGS="-I/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/include"\r\n\r\ncd Python-3.11.6\r\n/configure --prefix=/Bioinfo/Pipeline/SoftWare/python-3.11.6 ......\r\nmake && make install\r\n```\r\n\r\n![python3-confiigure-tkinter-yes](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/python-3-tkinter.png)\r\n\r\n对于 Python 3.10.x (及以下版本,如 Python-3.9.18),`configure` 中 `--with-tcltk-includes` 和 `--with-tcltk-libs` 的具体使用参考 : \r\n \r\n![tcltk-issue-21887-msg](https://kg.weiyan.cc/2024/10/tcltk-issue-21887-msg.webp)\r\n\r\n### Python 2\r\n\r\n想要在 Python 2.7 安装 Tkinter,需要在编译过程中通过 `--with-tcltk-includes` 和 `--with-tcltk-libs` 中指定 ActiveTcl 的头文件以及库所在路径。\r\n\r\n如果在执行编译安装过程中,出现无法找到 libXss.so.1 共享动态库报错:\r\n\r\n```bash\r\n$ tar zvxf Python-2.7.15.tgz\r\n$ cd Python-2.7.15\r\n$ ./configure --prefix=/usr/local/software/python-2.7 --with-tcltk-includes=\'-I/usr/local/software/ActiveTcl-8.6/include\' --with-tcltk-libs=\'-L/usr/local/software/ActiveTcl-8.6/lib -ltcl8.6 -ltk8.6\' --enable-optimizations\r\n$ make\r\n\r\n......\r\n\r\nwarning: building with the bundled copy of libffi is deprecated on this platform. It will not be distributed with Python 3.7\r\n*** WARNING: renaming "_tkinter" since importing it failed: libXss.so.1: cannot open shared object file: No such file or directory\r\n\r\nPython build finished successfully!\r\nThe necessary bits to build these optional modules were not found:\r\n_dbm _gdbm\r\nTo find the necessary bits, look in setup.py in detect_modules() for the module\'s name.\r\n\r\nThe following modules found by detect_modules() in setup.py, have been\r\nbuilt by the Makefile instead, as configured by the Setup files:\r\natexit pwd time\r\n\r\nFollowing modules built successfully but were removed because they could not be imported:\r\n_tkinter\r\n\r\nrunning build_scripts\r\n\r\n......\r\n```\r\n\r\nCentOS 下请参考以下解决方法:\r\n```\r\n$ sudo yum install libXScrnSaver libXScrnSaver-devel\r\n```\r\n\r\n## 调用 Tkinter\r\n\r\nPython 2/3 重新编译完后,执行一下下面的命令即可显示 Tk 的 ui 界面,以及相应的 Tcl/Tk 版本。\r\n```\r\npython2 -m Tkinter # python 2\r\npython3 -m tkinter # python 3\r\n```\r\n![python2-m-Tkinter](https://shub.weiyan.tech/yuque/elog-cookbook-img/FgBtb14ZgZFZXIRhOdt6efbYz7fd.png)\r\n\r\n这时候,我们重新运行开头的 GUI 界面程序,可以看到中文已经正常显示:\r\n![](https://shub.weiyan.tech/yuque/elog-cookbook-img/FqRHUXczPdHrQjFUXNQr_Cg_j2B4.png)\r\n\r\n## 参考资料\r\n\r\n- Download And Install Tcl: ActiveTcl,\r\n- Installing Tk,\r\n- Python 下"No module named \\_tkinter"问题解决过程分析,\r\n- Python GUI 编程(Tkinter)文件对话框,\r\n', 'bodyText': '主要是因为下面这两个原因,所以决定从源码编译安装去折腾一下 tkinter,以下是一些记录。\n_tkinter not found\nPython 3 源码编译安装,执行 make 过程中提示 _tkinter not found,如下:\n$ make\n......\nPython build finished successfully!\nThe necessary bits to build these optional modules were not found:\n_tkinter \n中文乱码\n使用 Anaconda 3(conda 4.5.11)的 tkinter python 包(conda install -c conda-forge tk)开发 GUI 界面程序过程中,发现 UI 界面出现的中文 Unicode 乱码一直没办法解决。\n#-*- coding: utf-8 -*-\n\nimport sys\n\nfrom tkinter import *\ntop=Tk()\ntop.wm_title("菜单")\ntop.geometry("800x600+300+100") # 创建一个菜单项,类似于导航栏\nmenubar=Menu(top) # 创建菜单项\nfmenu1=Menu(top)\n# 如果该菜单时顶层菜单的一个菜单项,则它添加的是下拉菜单的菜单\nfor item in [\'新建文件\', \'打开文件\',\'结果保存\']:\n fmenu1.add_command(label=item)\n\nfmenu2=Menu(top)\nfor item in [\'程序设置\',\'程序运行\']:\n fmenu2.add_command(label=item)\n\nfmenu3=Menu(top)\nfor item in [\'使用教程\', \'版权信息\', \'检查更新\']:\n fmenu3.add_command(label=item)\n\n# add_cascade 的一个很重要的属性就是 menu 属性,它指明了要把那个菜单级联到该菜单项上\n# 当然,还必不可少的就是 label 属性,用于指定该菜单项的名称\nmenubar.add_cascade(label=\'文件\', menu=fmenu1)\nmenubar.add_cascade(label="程序", menu=fmenu2)\nmenubar.add_cascade(label="帮助", menu=fmenu3)\n\n# 最后可以用窗口的 menu 属性指定我们使用哪一个作为它的顶层菜单\ntop[\'menu\']=menubar\ntop.mainloop()\n\n我们也可以确认一下是不是 Tk 本身的问题:\necho \'pack [button .h -text "Hello, World! 显示中文" -command exit]\' | wish\n\n\n\n正常显示\n\n\n\n中文乱码\n\n\n\n一些参考资料:\n\nPython 3.x 中文编码转换的问题:https://bbs.bccn.net/thread-479560-1-1.html\nPython 2.6 Tk 中文乱码解決方法:http://blogkrogh.blogspot.com/2011/03/python-26-tk.html\ntkinter 乱码,pyqt4 乱码:http://aboutweb.lofter.com/post/11743e_6f7e4a5\n\n上面几种方法测试后,问题依然存在。在 google 上一番搜索和来回测试之后,发现了几点信息:\n\n有人说,可能是 tcl/tk 安装不完整造成的。\ntcl/tk 重装后需要对 Python 重新编译 tkinter 才能起作用。\nconda install -c conda-forge tk,虽然没有任何报错,python2 中 import tkinter 也正常,但 conda 的软件安装就像一个黑盒子,无法确认 tcl/tk 是否完整安装。\npython 的 PyPI 仓库中是没有 tkinter 包的,想要使用 pip install tkinter 卸载或者重装都是行不通的。\n网上也有人说可以使用 yum install python3-tk/python-tk 解决,但对于本人来说,没用。\n\n什么是 tcl, tk, tkinter\n\nThe\xa0tkinter\xa0package (“Tk interface”) is the standard Python interface to the Tk GUI toolkit. Both Tk and\xa0tkinter\xa0are available on most Unix platforms, as well as on Windows systems. (Tk itself is not part of Python; it is maintained at ActiveState.)\nRunning\xa0python\xa0-m\xa0tkinter\xa0from the command line should open a window demonstrating a simple Tk interface, letting you know that\xa0tkinter\xa0is properly installed on your system, and also showing what version of Tcl/Tk is installed, so you can read the Tcl/Tk documentation specific to that version.\nFrom https://docs.python.org/3/library/tkinter.html\n\nTcl 是"工具控制语言(Tool Control Language)"的缩写。Tk 是 Tcl "图形工具箱" 的扩展,它提供各种标准的 GUI 接口项,以利于迅速进行高级应用程序开发。\ntkinter 包("Tk 接口")是 Tk GUI 工具包的标准 Python 接口。 Tk 和 \xa0tkinter 在大多数 Unix 平台以及 Windows 系统上都可用(Tk 本身不是 Python 的一部分,它在 ActiveState 中维护)。您可以通过从命令行运行 \xa0python -m\xa0tkinter来检查 \xa0tkinter 是否已正确安装在系统上。如果已经安装该命令会打开一个简单的 Tk 界面,该界面除了让我们知道 tkinter 已正确安装,并且还显示安装了哪个版本的 Tcl/Tk,因此我们可以阅读特定于该版本的 Tcl/Tk 文档。\n\n如果 \xa0tkinter\xa0 没有安装,则会提示找不到该包(注意在 Python 2 中该包包名为 Tkinter,Python 3 中为 tkinter):\n\n接下来我们将尝试在 Python 2/3 中安装 Tcl/Tk,并重新编译 Python 2/3,已完成 Tkinter 安装(tkinter 为 Python 的标准库,标准库的安装需要重新编译 Python ?)。\nActiveTcl 安装\nActiveTcl 是 ActiveState 发布的关于 Tcl/Tk 的发行版本,该发行版本包含了最新版本的 Tk 和 Tcl 程序,我们下载其免费的社区版本进行安装即可。\n参考下载链接:https://www.activestate.com/products/activetcl/downloads/\n参考安装教程:https://tkdocs.com/tutorial/install.html\n以下为 CentOS 6.5 下 ActiveTcl-8.6.9 的一些安装记录,仅作参考。\n$ curl -fL "https://shenweiyan-generic.pkg.coding.net/btscl/activetcl/ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d.tar.gz?version=8.6.9.8609.2" -o ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d.tar.gz\n$ tar zvxf ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d.tar.gz\n$ cd ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d\n$ ./install.sh\n......\nCancel [no] => [RET]\nAccept License [yes] => \'A\' >>A\n\nPlease specify the installation directory.\nPath [/opt/ActiveTcl-8.6]: /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9\n\nPlease specify the directory for the demos.\nPath [/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/demos]:\n\nPlease specify the runtime installation directory.\n\nThis is the directory the applications will see as their installation directory\nwhen searching for packages and libraries, instead of the directory the files\nwere copied to. In most circumstances this is the same as the installation\ndirectory chosen before.\nPath [/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9]:\n\nPress return to begin installation\n Installation Directory: /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9\n Demos Directory: /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/demos\n Runtime Directory: See Installation Directory\nCancel => C\nNext => [RET] >>\n\nInstalling ActiveTcl ...\n Creating directory /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/share ...\n Creating directory /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/share/man ...\n ......\n\nPlease do not forget to extend your PATH and MANPATH variables to\nget access to the applications and manpages distributed with ActiveTcl.\n\nFor a csh or compatible perform\n setenv PATH "/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/bin:$PATH"\n\nFor a sh or similar perform\n PATH="/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/bin:$PATH"\n export PATH\n\nSome shells (bash for example) allow\n export PATH="/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/bin:$PATH"\n\nSimilar changes are required for MANPATH\nFinish >>\nActiveTcl 安装完成后,需要把 path 添加至环境变量(~/.bashrc):\nexport PATH="/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/bin:$PATH"\n\nTcl/Tk\n我们也可以直接去 https://sourceforge.net/projects/tcl/files/Tcl/ 直接通过源码的方式去编译安装 Tcl/Tk,尤其是当你的系统版本比较低,需要低版本的 Tcl/Tk,这种方法会比较合适。\n以 tcl8.5.19-src.tar.gz/tk8.5.19-src.tar.gz 为例,下载完成后,直接解压,然后执行常规安装即可。\ncd tcl8.5.19/unix\n./configure\nmake\nmake test\nmake install\n\nPython 重新编译安装\n参考:What’s New In Python 3.11 - doc.python.org\n\n📢 注意:\n\nPython 3.11.x 起(如 Python-3.11.3)中的 configure 已经把 --with-tcltk-includes和--with-tcltk-libs这两个参数移除!并使用 TCLTK_CFLAGS 和 TCLTK_LIBS 替代!!!\nPython 3.10.x (及以下版本,如 Python-3.9.16) 以及 Python 2.x.x 在 configure 中 --with-tcltk-includes和--with-tcltk-libs都是有的,通过这两个参数可以解决 Tkinter 的问题!!!\n\n\nPython 3\n这里以 Python-3.11.6 为例,参考 Python 3.11.0 install doesn’t recognize homebrew Tcl/Tk due to --with-tcltk-libs, --with-tcltk-includes switches being removed from 3.11 - pyenv#2499,在编译安装过程中使用 TCLTK_CFLAGS 和 TCLTK_LIBS 解决 _tkinter 缺失的问题。\nexport TCLTK_LIBS="-L/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/lib -ltcl8.6 -ltk8.6" # 8.5.x 版本,需改为 -ltcl8.5 -ltk8.5\nexport TCLTK_CFLAGS="-I/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/include"\n\ncd Python-3.11.6\n/configure --prefix=/Bioinfo/Pipeline/SoftWare/python-3.11.6 ......\nmake && make install\n\n\n对于 Python 3.10.x (及以下版本,如 Python-3.9.18),configure 中 --with-tcltk-includes 和 --with-tcltk-libs 的具体使用参考 https://bugs.python.org/issue21887:\n\nPython 2\n想要在 Python 2.7 安装 Tkinter,需要在编译过程中通过 --with-tcltk-includes 和 --with-tcltk-libs 中指定 ActiveTcl 的头文件以及库所在路径。\n如果在执行编译安装过程中,出现无法找到 libXss.so.1 共享动态库报错:\n$ tar zvxf Python-2.7.15.tgz\n$ cd Python-2.7.15\n$ ./configure --prefix=/usr/local/software/python-2.7 --with-tcltk-includes=\'-I/usr/local/software/ActiveTcl-8.6/include\' --with-tcltk-libs=\'-L/usr/local/software/ActiveTcl-8.6/lib -ltcl8.6 -ltk8.6\' --enable-optimizations\n$ make\n\n......\n\nwarning: building with the bundled copy of libffi is deprecated on this platform. It will not be distributed with Python 3.7\n*** WARNING: renaming "_tkinter" since importing it failed: libXss.so.1: cannot open shared object file: No such file or directory\n\nPython build finished successfully!\nThe necessary bits to build these optional modules were not found:\n_dbm _gdbm\nTo find the necessary bits, look in setup.py in detect_modules() for the module\'s name.\n\nThe following modules found by detect_modules() in setup.py, have been\nbuilt by the Makefile instead, as configured by the Setup files:\natexit pwd time\n\nFollowing modules built successfully but were removed because they could not be imported:\n_tkinter\n\nrunning build_scripts\n\n......\nCentOS 下请参考以下解决方法:\n$ sudo yum install libXScrnSaver libXScrnSaver-devel\n\n调用 Tkinter\nPython 2/3 重新编译完后,执行一下下面的命令即可显示 Tk 的 ui 界面,以及相应的 Tcl/Tk 版本。\npython2 -m Tkinter # python 2\npython3 -m tkinter # python 3\n\n\n这时候,我们重新运行开头的 GUI 界面程序,可以看到中文已经正常显示:\n\n参考资料\n\nDownload And Install Tcl: ActiveTcl,https://www.activestate.com/products/activetcl/downloads/\nInstalling Tk,https://tkdocs.com/tutorial/install.html\nPython 下"No module named _tkinter"问题解决过程分析,https://www.jianshu.com/p/0baa9657377f\nPython GUI 编程(Tkinter)文件对话框,https://my.oschina.net/u/2245781/blog/661533', 'bodyHTML': '

主要是因为下面这两个原因,所以决定从源码编译安装去折腾一下 tkinter,以下是一些记录。

\n

_tkinter not found

\n

Python 3 源码编译安装,执行 make 过程中提示 _tkinter not found,如下:

\n
$ make\n......\nPython build finished successfully!\nThe necessary bits to build these optional modules were not found:\n_tkinter 
\n

中文乱码

\n

使用 Anaconda 3(conda 4.5.11)的 tkinter python 包(conda install -c conda-forge tk)开发 GUI 界面程序过程中,发现 UI 界面出现的中文 Unicode 乱码一直没办法解决。

\n
#-*- coding: utf-8 -*-\n\nimport sys\n\nfrom tkinter import *\ntop=Tk()\ntop.wm_title("菜单")\ntop.geometry("800x600+300+100") # 创建一个菜单项,类似于导航栏\nmenubar=Menu(top) # 创建菜单项\nfmenu1=Menu(top)\n# 如果该菜单时顶层菜单的一个菜单项,则它添加的是下拉菜单的菜单\nfor item in [\'新建文件\', \'打开文件\',\'结果保存\']:\n    fmenu1.add_command(label=item)\n\nfmenu2=Menu(top)\nfor item in [\'程序设置\',\'程序运行\']:\n    fmenu2.add_command(label=item)\n\nfmenu3=Menu(top)\nfor item in [\'使用教程\', \'版权信息\', \'检查更新\']:\n    fmenu3.add_command(label=item)\n\n# add_cascade 的一个很重要的属性就是 menu 属性,它指明了要把那个菜单级联到该菜单项上\n# 当然,还必不可少的就是 label 属性,用于指定该菜单项的名称\nmenubar.add_cascade(label=\'文件\', menu=fmenu1)\nmenubar.add_cascade(label="程序", menu=fmenu2)\nmenubar.add_cascade(label="帮助", menu=fmenu3)\n\n# 最后可以用窗口的 menu 属性指定我们使用哪一个作为它的顶层菜单\ntop[\'menu\']=menubar\ntop.mainloop()
\n

\n

我们也可以确认一下是不是 Tk 本身的问题:

\n
echo \'pack [button .h -text "Hello, World! 显示中文" -command exit]\' | wish\n
\n
    \n
  • \n

    正常显示
    \nTK 正常显示

    \n
  • \n
  • \n

    中文乱码
    \nTK 中文乱码

    \n
  • \n
\n

一些参考资料:

\n\n

上面几种方法测试后,问题依然存在。在 google 上一番搜索和来回测试之后,发现了几点信息:

\n
    \n
  • 有人说,可能是 tcl/tk 安装不完整造成的。
  • \n
  • tcl/tk 重装后需要对 Python 重新编译 tkinter 才能起作用。
  • \n
  • conda install -c conda-forge tk,虽然没有任何报错,python2 中 import tkinter 也正常,但 conda 的软件安装就像一个黑盒子,无法确认 tcl/tk 是否完整安装。
  • \n
  • python 的 PyPI 仓库中是没有 tkinter 包的,想要使用 pip install tkinter 卸载或者重装都是行不通的。
  • \n
  • 网上也有人说可以使用 yum install python3-tk/python-tk 解决,但对于本人来说,没用。
  • \n
\n

什么是 tcl, tk, tkinter

\n
\n

The\xa0tkinter\xa0package (“Tk interface”) is the standard Python interface to the Tk GUI toolkit. Both Tk and\xa0tkinter\xa0are available on most Unix platforms, as well as on Windows systems. (Tk itself is not part of Python; it is maintained at ActiveState.)

\n

Running\xa0python\xa0-m\xa0tkinter\xa0from the command line should open a window demonstrating a simple Tk interface, letting you know that\xa0tkinter\xa0is properly installed on your system, and also showing what version of Tcl/Tk is installed, so you can read the Tcl/Tk documentation specific to that version.

\n

From https://docs.python.org/3/library/tkinter.html

\n
\n

Tcl 是"工具控制语言(Tool Control Language)"的缩写。Tk 是 Tcl "图形工具箱" 的扩展,它提供各种标准的 GUI 接口项,以利于迅速进行高级应用程序开发。

\n

tkinter 包("Tk 接口")是 Tk GUI 工具包的标准 Python 接口。 Tk 和 \xa0tkinter 在大多数 Unix 平台以及 Windows 系统上都可用(Tk 本身不是 Python 的一部分,它在 ActiveState 中维护)。您可以通过从命令行运行 \xa0python -m\xa0tkinter来检查 \xa0tkinter 是否已正确安装在系统上。如果已经安装该命令会打开一个简单的 Tk 界面,该界面除了让我们知道 tkinter 已正确安装,并且还显示安装了哪个版本的 Tcl/Tk,因此我们可以阅读特定于该版本的 Tcl/Tk 文档。

\n

\n

如果 \xa0tkinter\xa0 没有安装,则会提示找不到该包(注意在 Python 2 中该包包名为 Tkinter,Python 3 中为 tkinter):

\n

\n

接下来我们将尝试在 Python 2/3 中安装 Tcl/Tk,并重新编译 Python 2/3,已完成 Tkinter 安装(tkinter 为 Python 的标准库,标准库的安装需要重新编译 Python ?)。

\n

ActiveTcl 安装

\n

ActiveTcl 是 ActiveState 发布的关于 Tcl/Tk 的发行版本,该发行版本包含了最新版本的 Tk 和 Tcl 程序,我们下载其免费的社区版本进行安装即可。

\n

参考下载链接:https://www.activestate.com/products/activetcl/downloads/
\n参考安装教程:https://tkdocs.com/tutorial/install.html

\n

以下为 CentOS 6.5 下 ActiveTcl-8.6.9 的一些安装记录,仅作参考。

\n
$ curl -fL "https://shenweiyan-generic.pkg.coding.net/btscl/activetcl/ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d.tar.gz?version=8.6.9.8609.2" -o ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d.tar.gz\n$ tar zvxf ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d.tar.gz\n$ cd ActiveTcl-8.6.9.8609.2-x86_64-linux-glibc-2.5-dcd3ff05d\n$ ./install.sh\n......\nCancel         [no]  => [RET]\nAccept License [yes] => \'A\' >>A\n\nPlease specify the installation directory.\nPath [/opt/ActiveTcl-8.6]: /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9\n\nPlease specify the directory for the demos.\nPath [/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/demos]:\n\nPlease specify the runtime installation directory.\n\nThis is the directory the applications will see as their installation directory\nwhen searching for packages and libraries, instead of the directory the files\nwere copied to. In most circumstances this is the same as the installation\ndirectory chosen before.\nPath [/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9]:\n\nPress return to begin installation\n     Installation Directory:  /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9\n     Demos Directory:         /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/demos\n     Runtime Directory:       See Installation Directory\nCancel => C\nNext   => [RET] >>\n\nInstalling ActiveTcl ...\n        Creating directory /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/share ...\n        Creating directory /Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/share/man ...\n        ......\n\nPlease do not forget to extend your PATH and MANPATH variables to\nget access to the applications and manpages distributed with ActiveTcl.\n\nFor a csh or compatible perform\n    setenv PATH "/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/bin:$PATH"\n\nFor a sh or similar perform\n    PATH="/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/bin:$PATH"\n    export PATH\n\nSome shells (bash for example) allow\n    export PATH="/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/bin:$PATH"\n\nSimilar changes are required for MANPATH\nFinish >>
\n

ActiveTcl 安装完成后,需要把 path 添加至环境变量(~/.bashrc):

\n
export PATH="/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/bin:$PATH"\n
\n

Tcl/Tk

\n

我们也可以直接去 https://sourceforge.net/projects/tcl/files/Tcl/ 直接通过源码的方式去编译安装 Tcl/Tk,尤其是当你的系统版本比较低,需要低版本的 Tcl/Tk,这种方法会比较合适。

\n

以 tcl8.5.19-src.tar.gz/tk8.5.19-src.tar.gz 为例,下载完成后,直接解压,然后执行常规安装即可。

\n
cd tcl8.5.19/unix\n./configure\nmake\nmake test\nmake install\n
\n

Python 重新编译安装

\n

参考:What’s New In Python 3.11 - doc.python.org

\n
\n

📢 注意:

\n
    \n
  1. Python 3.11.x 起(如 Python-3.11.3)中的 configure 已经把 --with-tcltk-includes--with-tcltk-libs这两个参数移除!并使用 TCLTK_CFLAGSTCLTK_LIBS 替代!!!
  2. \n
  3. Python 3.10.x (及以下版本,如 Python-3.9.16) 以及 Python 2.x.x 在 configure--with-tcltk-includes--with-tcltk-libs都是有的,通过这两个参数可以解决 Tkinter 的问题!!!
  4. \n
\n
\n

Python 3

\n

这里以 Python-3.11.6 为例,参考 Python 3.11.0 install doesn’t recognize homebrew Tcl/Tk due to --with-tcltk-libs, --with-tcltk-includes switches being removed from 3.11 - pyenv#2499,在编译安装过程中使用 TCLTK_CFLAGSTCLTK_LIBS 解决 _tkinter 缺失的问题。

\n
export TCLTK_LIBS="-L/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/lib -ltcl8.6 -ltk8.6"  # 8.5.x 版本,需改为 -ltcl8.5 -ltk8.5\nexport TCLTK_CFLAGS="-I/Bioinfo/Pipeline/SoftWare/ActiveTcl-8.6.9/include"\n\ncd Python-3.11.6\n/configure --prefix=/Bioinfo/Pipeline/SoftWare/python-3.11.6 ......\nmake && make install\n
\n

python3-confiigure-tkinter-yes

\n

对于 Python 3.10.x (及以下版本,如 Python-3.9.18),configure--with-tcltk-includes--with-tcltk-libs 的具体使用参考 https://bugs.python.org/issue21887

\n

tcltk-issue-21887-msg

\n

Python 2

\n

想要在 Python 2.7 安装 Tkinter,需要在编译过程中通过 --with-tcltk-includes--with-tcltk-libs 中指定 ActiveTcl 的头文件以及库所在路径。

\n

如果在执行编译安装过程中,出现无法找到 libXss.so.1 共享动态库报错:

\n
$ tar zvxf Python-2.7.15.tgz\n$ cd Python-2.7.15\n$ ./configure --prefix=/usr/local/software/python-2.7 --with-tcltk-includes=\'-I/usr/local/software/ActiveTcl-8.6/include\' --with-tcltk-libs=\'-L/usr/local/software/ActiveTcl-8.6/lib -ltcl8.6 -ltk8.6\' --enable-optimizations\n$ make\n\n......\n\nwarning: building with the bundled copy of libffi is deprecated on this platform.  It will not be distributed with Python 3.7\n*** WARNING: renaming "_tkinter" since importing it failed: libXss.so.1: cannot open shared object file: No such file or directory\n\nPython build finished successfully!\nThe necessary bits to build these optional modules were not found:\n_dbm                  _gdbm\nTo find the necessary bits, look in setup.py in detect_modules() for the module\'s name.\n\nThe following modules found by detect_modules() in setup.py, have been\nbuilt by the Makefile instead, as configured by the Setup files:\natexit                pwd                   time\n\nFollowing modules built successfully but were removed because they could not be imported:\n_tkinter\n\nrunning build_scripts\n\n......
\n

CentOS 下请参考以下解决方法:

\n
$ sudo yum install libXScrnSaver libXScrnSaver-devel\n
\n

调用 Tkinter

\n

Python 2/3 重新编译完后,执行一下下面的命令即可显示 Tk 的 ui 界面,以及相应的 Tcl/Tk 版本。

\n
python2 -m Tkinter   # python 2\npython3 -m tkinter   # python 3\n
\n

python2-m-Tkinter

\n

这时候,我们重新运行开头的 GUI 界面程序,可以看到中文已经正常显示:
\n

\n

参考资料

\n', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '1.3.5-Python'}]}, 'comments': {'nodes': []}}, {'title': '飞书文档初体验', 'number': 11, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/11', 'createdAt': '2023-10-24T07:57:52Z', 'lastEditedAt': '2023-12-01T02:24:27Z', 'updatedAt': '2024-01-04T05:44:25Z', 'body': '2023 年的 1024 程序员节前一天,语雀服务器崩溃长达 8 个小时的余温还没消,就迫不及待再去体验了一把飞书文档,说几点个人感受。\r\n\r\n\r\n\r\n![20231023-yuque](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/Gitbook/2023/20231023-yuque.png)\r\n\r\n- [如何看待语雀因网络故障导致用户无法正常访问文档?在线文档的可靠性还值得信任吗?](https://www.zhihu.com/question/627418678) - 知乎\r\n- [鉴于昨天的语雀,有啥推荐的笔记软件么](https://www.v2ex.com/t/984728) -V2EX\r\n\r\n\r\n首先,飞书文档[国内版本](https://www.feishu.cn/)和[国际版本](https://www.larksuite.com/)的区别可不是一般的大。\r\n\r\n![飞书文档国内版本](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/Gitbook/2023/feishu-cn-admin.png)\r\n\r\n![飞书文档国际版本](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/Gitbook/2023/larksuite-admin.png)\r\n\r\n第二,书写体验相当不错。\r\n\r\n第三,最然支持 Markdown 所见即所得的编辑模式,但没法查看单篇文档的 Markdown,这也是我最不满意的地方。\r\n\r\n第四,API 很强大,文档很丰富,但没找到怎么通过 API 获取 wiki 知识库内容的介绍!\r\n\r\n截止 2023.10.25 了解到飞书目前是没有 wiki 知识库内容的 API 接口,不清楚后面是否会有这方面的支持,且持续关注中。\r\n\r\n![飞书文档 wiki 知识库 API](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/KGarden/2023/feishu-wiki-api.png)\r\n\r\n事实上,飞书是支持 通过 API 接口获取 wiki 知识库内容的(上面截图中客服的回答并不准确),具体可以参考 [Feishu Pages](https://github.com/longbridgeapp/feishu-pages#feishu-pages) 实现 wiki 知识库的内容导出。\r\n\r\n第五,经历语雀宕机事件,不得不考虑多平台备份的问题,对于飞书文档目前没发现比较好的方法。\r\n\r\n经过了这个事件很多人都对在线文档产生了一些动摇,但总体来说在使用性和方便性上在线文档还是很有优势的,但值得注意的是不能把所有的鸡蛋都放到一个篮子 —— 备份很重要!**通用格式** 和 **数据可控** 或者可以成为一个评判的基础,那些过于封闭不支持导出(甚至是批量导出)的平台基本可以放弃了。\r\n', 'bodyText': '2023 年的 1024 程序员节前一天,语雀服务器崩溃长达 8 个小时的余温还没消,就迫不及待再去体验了一把飞书文档,说几点个人感受。\n\n\n\n如何看待语雀因网络故障导致用户无法正常访问文档?在线文档的可靠性还值得信任吗? - 知乎\n鉴于昨天的语雀,有啥推荐的笔记软件么 -V2EX\n\n首先,飞书文档国内版本和国际版本的区别可不是一般的大。\n\n\n第二,书写体验相当不错。\n第三,最然支持 Markdown 所见即所得的编辑模式,但没法查看单篇文档的 Markdown,这也是我最不满意的地方。\n第四,API 很强大,文档很丰富,但没找到怎么通过 API 获取 wiki 知识库内容的介绍!\n截止 2023.10.25 了解到飞书目前是没有 wiki 知识库内容的 API 接口,不清楚后面是否会有这方面的支持,且持续关注中。\n\n事实上,飞书是支持 通过 API 接口获取 wiki 知识库内容的(上面截图中客服的回答并不准确),具体可以参考 Feishu Pages 实现 wiki 知识库的内容导出。\n第五,经历语雀宕机事件,不得不考虑多平台备份的问题,对于飞书文档目前没发现比较好的方法。\n经过了这个事件很多人都对在线文档产生了一些动摇,但总体来说在使用性和方便性上在线文档还是很有优势的,但值得注意的是不能把所有的鸡蛋都放到一个篮子 —— 备份很重要!通用格式 和 数据可控 或者可以成为一个评判的基础,那些过于封闭不支持导出(甚至是批量导出)的平台基本可以放弃了。', 'bodyHTML': '

2023 年的 1024 程序员节前一天,语雀服务器崩溃长达 8 个小时的余温还没消,就迫不及待再去体验了一把飞书文档,说几点个人感受。

\n\n

20231023-yuque

\n\n

首先,飞书文档国内版本国际版本的区别可不是一般的大。

\n

飞书文档国内版本

\n

飞书文档国际版本

\n

第二,书写体验相当不错。

\n

第三,最然支持 Markdown 所见即所得的编辑模式,但没法查看单篇文档的 Markdown,这也是我最不满意的地方。

\n

第四,API 很强大,文档很丰富,但没找到怎么通过 API 获取 wiki 知识库内容的介绍!

\n

截止 2023.10.25 了解到飞书目前是没有 wiki 知识库内容的 API 接口,不清楚后面是否会有这方面的支持,且持续关注中。

\n

飞书文档 wiki 知识库 API

\n

事实上,飞书是支持 通过 API 接口获取 wiki 知识库内容的(上面截图中客服的回答并不准确),具体可以参考 Feishu Pages 实现 wiki 知识库的内容导出。

\n

第五,经历语雀宕机事件,不得不考虑多平台备份的问题,对于飞书文档目前没发现比较好的方法。

\n

经过了这个事件很多人都对在线文档产生了一些动摇,但总体来说在使用性和方便性上在线文档还是很有优势的,但值得注意的是不能把所有的鸡蛋都放到一个篮子 —— 备份很重要!通用格式数据可控 或者可以成为一个评判的基础,那些过于封闭不支持导出(甚至是批量导出)的平台基本可以放弃了。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.2-好玩'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'WebStack-Hugo | 一个静态响应式导航主题', 'number': 10, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/10', 'createdAt': '2023-10-23T08:25:32Z', 'lastEditedAt': '2024-11-05T01:44:19Z', 'updatedAt': '2024-11-05T01:44:19Z', 'body': '> Via:[我给自己做了一个导航网站](https://mp.weixin.qq.com/s/gVWGjxG9qd7qSyX3N8Zgag) | [BioIT爱好者](https://www.bioitee.com) \r\n\r\n
\r\n\r\n**📢 让更多人的人制作自己的导航网站。如果你觉得本主题对你有所帮助,欢迎请作者 [喝杯咖啡](https://kg.weiyan.cc/0000/img/donate.webp) >.<**\r\n\r\n## 主题开源地址 \r\n\r\n[**GitHub**](https://github.com/shenweiyan/WebStack-Hugo) | [**Gitee**](https://gitee.com/shenweiyan/WebStack-Hugo) | [**GitCode**](https://gitcode.com/shenweiyan/WebStack-Hugo)\r\n\r\n## 主题展示地址\r\n\r\n[**WebStack-Hugo 网址导航**](https://bioit.top/) | [**生信网址导航**](https://hao.bioitee.com/) \r\n\r\n## 为什么做这个网站\r\n\r\n之所以想着要给自己倒腾一个导航网站,主要有几个原因:\r\n\r\n- 购买了一个域名,且也备案成功了,总想折腾点跟它有关的事情;\r\n- 经常在公司、家里(有时候还有其他的临时场所)更换电脑,每次同步书签(或者登陆一些导航网站)需要各种登陆,麻烦。\r\n\r\n说干就干,从 [WebStack 的开源项目](https://github.com/WebStackPage/WebStackPage.github.io)开始,断断续续的折腾了好几天,终于把轮子造起来了。\r\n\r\n\r\n\r\n\r\nwebstack-apple\r\n\r\n## 跟其他导航网站有什么区别\r\n\r\n这是 Hugo 版 WebStack 主题。可以借助 Github/Gitee Pages 或者云平台直接托管部署,无需服务器。\r\n\r\n本项目是基于纯静态的网址导航网站 [webstack.cc](https://github.com/WebStackPage/WebStackPage.github.io) 制作的 [Hugo](https://gohugo.io/) 主题,其中部分代码参考了以下几个开源项目:\r\n\r\n- [https://github.com/WebStackPage/WebStackPage.github.io](https://github.com/WebStackPage/WebStackPage.github.io)\r\n- [https://github.com/liutongxu/liutongxu.github.io](https://github.com/WebStackPage/WebStackPage.github.io)\r\n- [https://github.com/iplaycode/webstack-hugo](https://github.com/iplaycode/webstack-hugo)\r\n\r\n总体说一下特点:\r\n\r\n- 采用了一直以来最喜欢的 hugo 部署方式,方便高效。\r\n- 主要的配置信息都集成到了 **config.toml**,一键完成各种自定义的配置。\r\n- 导航的各个信息都集成在 **data/webstack.yml** 文件中,方便后续增删改动。\r\n\r\n```yaml\r\n- taxonomy: 科研办公\r\n icon: fas fa-flask fa-lg\r\n list:\r\n - term: 生物信息\r\n links:\r\n - title: NCBI\r\n logo: n/ncbi.jpg\r\n url: https://www.ncbi.nlm.nih.gov/\r\n description: National Center for Biotechnology Information.\r\n - title: Bioconda\r\n logo: b/bioconda.jpg\r\n url: https://anaconda.org/bioconda/\r\n description: "Bioconda :: Anaconda.org."\r\n - term: 云服务器\r\n links:\r\n - title: 阿里云\r\n logo: a/aliyun.jpg\r\n url: https://www.aliyun.com/\r\n description: 上云就上阿里云。\r\n - title: 腾讯云\r\n logo: c/cloud-tencent.jpg\r\n url: https://cloud.tencent.com/\r\n description: 产业智变,云启未来。\r\n```\r\n\r\n- 做了手机电脑自适应以及夜间模式。\r\n- 增加了搜索功能,以及下拉的热词选项(基于百度 API)。\r\n- 增加了一言、和风天气的 API(和风天气 API 已经官方已经不再支持,目前还没到到替代)。\r\n\r\n## Windows 下安装部署\r\n\r\n本安装部署在 Windows 7 x64 上测试没问题,相关操作同样适用于 Windows 10,如有任何问题,欢迎留言或者微信与我联系。\r\n\r\n### 第一,下载 hugo\r\n\r\n下载链接:[https://github.com/gohugoio/hugo/releases](https://github.com/gohugoio/hugo/releases),在这里我们下载 [hugo_0.89.4_Windows-64bit.zip](https://github.com/gohugoio/hugo/releases/download/v0.89.4/hugo_0.89.4_Windows-64bit.zip)。\r\n\r\n![download-hugo-windows](https://kg.weiyan.cc/2023/11/download-hugo-windows.png)\r\n\r\n### 第二,解压\r\n\r\n我们把 [hugo_0.89.4_Windows-64bit.zip](https://github.com/gohugoio/hugo/releases/download/v0.89.4/hugo_0.89.4_Windows-64bit.zip) 下载到 **F:\\WebStack** 目录下,然后解压到当前文件夹。\r\n\r\n解压完成后,在该目录会多出 `hugo.exe`、`LICENSE`、`README.md` 三个文件:\r\n\r\n![unzip hugo_0.89.4_Windows-64bit](https://kg.weiyan.cc/2023/11/unzip-hugo-0.89.4-windows-64bit.png)\r\n\r\n### 第三,检测是否安装成功\r\n\r\n通过下面的方法,检测 `hugo` 是否安装成功。\r\n\r\n> **🏷️ 温馨提示:**\r\n> \r\n> Windows 命令运行窗口中可以使用 Tab 进行命令行补全,例如你当前目录下有一个 WebStack-Hugo 目录,你在命令行窗口中输入一个 w 后按下 Tab 键,命令行就会自动出现 WebStack-Hugo!\r\n> \r\n> 使用命令行补全,可以减少代码(或者文件名)的输入,方便快捷,又能减少错误!\r\n\r\n1. 在 Windows 中使用 **Win+R** 打开“**运行**”对话框,在对话框中输入“**cmd**”,点击确认。\r\n\r\n ![win-r-cmd](https://kg.weiyan.cc/2023/11/win-r-cmd.png)\r\n\r\n2. 在 Windows 运行窗口,先切换盘符到 **F** 盘,然后进入 `hugo` 的解压缩目录(**F:\\WebStack**),具体操作如下。\r\n\r\n - 在光标处输入 **F:**,然后按回车;\r\n\r\n ![cmd-change-dir](https://kg.weiyan.cc/2023/11/cmd-change-dir.png)\r\n\r\n - 我们就将盘符切换为 **F** 盘;\r\n\r\n ![cmd-f-dir](https://kg.weiyan.cc/2023/11/cmd-f-dir.png)\r\n\r\n - 接着输入 **cd WebStack**,回车,就进入了 **F:\\WebStack** 目录;使用 **ls** 可以看到当前目录下的文件。\r\n\r\n ![webstack-win-ls](https://kg.weiyan.cc/2023/11/webstack-win-ls.png)\r\n\r\n - 最后,输入 **hugo.exe version**,回车,如图所示,则代表安装成功。\r\n\r\n ![hugo-exe-version](https://kg.weiyan.cc/2023/11/hugo-exe-version.png)\r\n\r\n### 第四,下载 WebStack-Hugo\r\n\r\n浏览器打开 [https://github.com/shenweiyan/WebStack-Hugo](https://github.com/shenweiyan/WebStack-Hugo),点击 Code 下的 **"Download ZIP"**,把 **WebStack-hugo-main.zip** 下载到刚才 hugo 解压缩的目录(**F:\\WebStack**)。\r\n\r\n![webstack-download-zip](https://kg.weiyan.cc/2023/11/webstack-download-zip.png)\r\n\r\n![webstack-hugo-main-zip](https://kg.weiyan.cc/2023/11/webstack-hugo-main-zip.png)\r\n\r\n### 第五,解压和重命名\r\n\r\n把 **WebStack-Hugo-main.zip** 解压到当前目录。\r\n\r\n![webstack-hugo-main-unzip](https://kg.weiyan.cc/2023/11/webstack-hugo-main-unzip.png)\r\n![webstack-hugo-main-rename](https://kg.weiyan.cc/2023/11/webstack-hugo-main-rename.png)\r\n\r\n### 第六,安装主题\r\n\r\n首先,进入 **F:\\WebStack** 目录;\r\n\r\n然后,创建一个 **themes** 的文件夹;\r\n\r\n![create-themes-dir](https://kg.weiyan.cc/2023/11/create-themes-dir.png)\r\n\r\n接着,把解压后的 **WebStack-Hugo** 整个文件夹移动到 **themes** 中。\r\n\r\n![mv-webstack-hugo-to-themes](https://kg.weiyan.cc/2023/11/mv-webstack-hugo-to-themes.png)\r\n\r\n第四,将 `themes/WebStack-Hugo/exampleSite` 目录下的所有文件复制到 hugo 站点根目录(即 `F:\\WebStack`)。\r\n\r\n![cp-examplesite](https://kg.weiyan.cc/2023/11/cp-examplesite.png)\r\n\r\n### 第七,启动预览\r\n\r\n在刚才已经打开的 Windows 命令运行窗口中,使用下面的命令执行 **hugo server**,启动站点——Hugo 可以启动一个 Web 服务器,同时构建站点内容到内存中并在检测到文件更改后重新渲染,方便我们在开发环境实时预览对站点所做的更改。\r\n\r\n```shell\r\nhugo.exe server\r\n```\r\n\r\n![hugo-exe-server](https://kg.weiyan.cc/2023/11/hugo-exe-server.png)\r\n\r\n最后,在浏览器中打开 [**http://127.0.0.1:1313/**](http://127.0.0.1:1313/),即可看到生成的站点。\r\n\r\n![webstack-hugo-1313](https://kg.weiyan.cc/2023/11/webstack-hugo-1313.png)\r\n\r\n## Linux 下安装部署\r\n\r\n安装完本 WebStack-Hugo 主题后,将 exampleSite 目录下的文件复制到 hugo 站点根目录,根据需要把 config.toml 的一些信息改成自己的,导航的网址信息可通过 data 目录下 webstack.yml 修改。\r\n\r\n具体执行步骤如下:\r\n\r\n```bash\r\nmkdir /home/shenweiyan/mysite\r\ncd /home/shenweiyan/mysite\r\n\r\n# 安装 WebStack-Hugo 主题\r\ngit clone https://github.com/shenweiyan/WebStack-Hugo.git themes/WebStack-Hugo\r\n\r\n# 将 exampleSite 目录下的文件复制到 hugo 站点根目录\r\ncd /home/shenweiyan/mysite\r\ncp -r themes/WebStack-Hugo/exampleSite/* ./\r\n\r\n# 启动 hugo 站点\r\nhugo server\r\n# 如果你知道你的公网 ip, 如下面的 132.76.230.31, 可以使用下面的方式执行 hugo server\r\nhugo server --baseUrl=132.76.230.31 --bind=0.0.0.0\r\n```\r\n\r\n也可以参考 [@jetsung](https://github.com/jetsung) 在 [pull 15](https://github.com/shenweiyan/WebStack-Hugo/pull/15) 所用的方法安装部署:\r\n\r\n```bash\r\n# 创建项目\r\nmkdir navsites\r\ncd $_\r\n\r\n# 初始化项目\r\ngit init\r\n\r\n# 将 WebStack-Hugo 源下载到 themes/WebStack-Hugo 文件夹\r\ngit submodule add https://github.com/shenweiyan/WebStack-Hugo.git themes/WebStack-Hugo\r\ncp -r themes/WebStack-Hugo/exampleSite/* ./\r\n\r\n# 安装 hugo\r\ngo install github.com/gohugoio/hugo@latest\r\n\r\n# 本地测试\r\nhugo server\r\n\r\n# 生成 docs 文件夹,将并静态内容生成至此处\r\nhugo -D\r\n```\r\n\r\n## 导出 HTML 静态资源\r\n\r\nWindows/Linux 下执行的 **hugo server** 命令将会通过热加载的方式临时启动一个 Hugo 服务器(Hugo 可以启动一个 Web 服务器,同时构建站点内容到内存中并在检测到文件更改后重新渲染,方便我们在开发环境实时预览对站点所做的更改),这个时候我们打开浏览器 [http://127.0.0.1:1313/](http://127.0.0.1:1313/),就可以看到我们站点的样子了。\r\n\r\n如果我们想要把我们的站点部署到 GitHub/Gitee Pages(或者本地的服务器),我们可以:\r\n\r\n### 1. 生成静态页面内容\r\n\r\n可以通过下面的命令,生成(构建)静态页面内容。\r\n\r\n```python\r\nhugo -D 或者 hugo --minify\r\n```\r\n\r\n这个命令会默认在 **`public/`** 目录中生成您的网站,当然您可以通过改变站点配置中的 **`publishDir`** 选项来配置这个输出目录。\r\n\r\n> **🏷️ Hugo 小知识 - 草案、未来和过期内容**\r\n> \r\n> Hugo 允许您在网站内容的前言设定中设置文档的`draft`,`publishdate`甚至`expirydate`字段。默认情况下,Hugo 不会发布下面内容:\r\n>\r\n> 1. `publishdate` 发布日期值设定在未来的内容;\r\n> 2. `draft:true` 草案状态设置为真的内容;\r\n> 3. `expirydate` 过期日期值设置为过去某事件的内容。\r\n>\r\n> 这三个可以在本地开发和部署编译时通过对`hugo`和`hugo server`分别添加如下参数来重新设定,或者在配置文件中设定对应(不包含`--`)域的 boolean 值:\r\n>\r\n> 1. -F, --buildFuture include content with publishdate in the future\r\n> 2. -D, --buildDrafts include content marked as draft\r\n> 3. -E, --buildExpired include expired content\r\n\r\n### 2. 部署站点\r\n\r\n把生成的 `public/` 静态内容目录上传到 GitHub,开启 GitHub/Gitee Pages,并且绑定 cname 域名即可。\r\n\r\n## 使用说明与技巧\r\n\r\n这是一个开源的公益项目,你可以拿来制作自己的网址导航,也可以做与导航无关的网站。\r\n\r\n### 左导航栏图标\r\n\r\n左侧、顶部导航栏图标用的都是 **Font Awesome** 图标库 **v5** 版本 **Free** 的图标。链接如下:\r\n\r\n🔗 [https://fontawesome.com/v5/search?o=r&m=free](https://fontawesome.com/v5/search?o=r&m=free)\r\n\r\n![fontawesome-v5-free](https://kg.weiyan.cc/2023/11/fontawesome-v5-free.png)\r\n\r\n### 调整头部搜索栏\r\n\r\n头部搜索栏的默认位置可以通过下面的方法进行修改。\r\n\r\n1. 直接修改 **layouts/partials/content_search.html**,调整对应部分的位置。\r\n2. 调整默认的搜索(即点击"常用/搜索/工具 ...." 时下指箭头的指向),把对应的 id 添加到对应的 label 里面。\r\n\r\n![set-default-search-bing](https://kg.weiyan.cc/2023/11/set-default-search-bing.png)\r\n![view-default-search-bing](https://kg.weiyan.cc/2023/11/view-default-search-bing.png)\r\n\r\n### 自定义头部导航\r\n\r\n[WebStack-Hugo](https://github.com/shenweiyan/WebStack-Hugo) 把头部的导航菜单的各个信息集成在了 **data/header.yml** 文件中,每个人可以根据自己的需要调整。\r\n\r\n```yaml\r\n- item: 首页\r\n icon: fa fa-home\r\n link: "./"\r\n\r\n- item: 作者\r\n icon: fa fa-book\r\n link: https://www.yuque.com/shenweiyan\r\n\r\n- item: 配置\r\n icon: fa fa-cog\r\n link: ""\r\n list:\r\n - name: 源码\r\n url: "#"\r\n - name: 图标\r\n url: "#"\r\n```\r\n\r\n### 获取网站图标\r\n\r\n[Bio & IT 网址导航](https://nav.bioitee.com/)默认使用的是个人收集的网站图标,主要是查看网站源码、百度、谷歌等途径把对应导航的图标下载下来,这个方法比较原始繁琐,适合导航不是很多的情况。\r\n\r\n#### 一为\r\n\r\n你也可以使用一为提供的的 [Favicon](https://www.iowen.cn/tag/favicon/) 图标 [API](https://www.iowen.cn/tag/api/):[获取网站 Favicon - 免费 API 数据接口调用服务平台](https://api.iowen.cn/doc/favicon.html)。\r\n\r\n**使用方法:**\r\n\r\n1. 获取 Favicon 图标\r\n```\r\nhttps://api.iowen.cn/favicon/www.iowen.cn.png\r\n```\r\n\r\n2. 刷新缓存\r\n```\r\nhttps://api.iowen.cn/favicon/www.iowen.cn.png?refresh=true\r\n```\r\n\r\n3. 将上方代码中的 `www.iowen.cn` 替换为你需要获取的网址域名。\r\n\r\n#### Favicon.im\r\n\r\n除了一为的 API,你也可以使用 来在网页中插入其他网站的 Favicon 图片,可以放大显示。\r\n\r\n![favicon-im](https://kg.weiyan.cc/2024/08/favicon-im.webp)\r\n\r\n#### Favicon Extractor\r\n\r\n类似网站 [Favicon Downloader](https://www.faviconextractor.com/),代码[开源](https://github.com/seadfeng/favicon-downloader)。\r\n\r\n![favicon-extractor](https://kg.weiyan.cc/2024/08/favicon-extractor.webp)\r\n\r\n\r\n## 已知问题\r\n\r\n1. 日间模式与夜间模式切换时候,头部搜索栏的背景图片切换不够流畅(个人的 js 知识有限,在 footer.html 做了一些简单的调整来实现),如果你有更好的想法,欢迎 PR 或者交流。\r\n\r\n## 感谢墙\r\n\r\n本主题的部分代码参考了以下几个开源项目,特此感谢。\r\n\r\n- [WebStackPage/WebStackPage.github.io](https://github.com/WebStackPage/WebStackPage.github.io)\r\n- [liutongxu/liutongxu.github.io](https://github.com/liutongxu/liutongxu.github.io)\r\n- [iplaycode/webstack-hugo](https://github.com/iplaycode/webstack-hugo)\r\n\r\n感谢 [WebStack](https://github.com/WebStackPage/WebStackPage.github.io) 的作者 [Viggo](https://twitter.com/decohack) 的肯定和[推广宣传](https://twitter.com/decohack/status/1569188705478516738)。\r\n\r\n![twitter-decohack-webstack-hugo](https://kg.weiyan.cc/2023/11/twitter-decohack-webstack-hugo.png)\r\n\r\n感谢以下所有朋友对本主题所做出的贡献。 \r\n**[@yanbeiyinhanghang](https://github.com/yinhanghang)** \r\n**[@jetsung](https://github.com/jetsung)** \r\n\r\n## 赞赏\r\n\r\n如果你觉得本项目对你有所帮助,欢迎请作者喝杯热咖啡 >.< \r\n\r\n![donate-wecaht-aliapy](https://kg.weiyan.cc/0000/img/donate.webp)\r\n\r\n## 反馈与交流\r\n\r\n最后,最重要的,秉承 WebStack 的宗旨,这是一个开源的公益项目,你可以拿来制作自己的网址导航,也可以做与导航无关的网站。\r\n\r\nWebStack 有非常多的魔改版本,这是其中一个。\r\n\r\n**如果你对本主题进行了一些个性化调整,欢迎在本项目中 **[**issues**](https://github.com/shenweiyan/WebStack-Hugo/issues)** 中一起分享交流!**\r\n\r\n**如果参考本主题构建了属于你自己的网址导航,欢迎在本评论区(或源码 **[**issues**](https://github.com/shenweiyan/WebStack-Hugo/issues)** 区)留下你网站的访问链接 >.<**\r\n', 'bodyText': 'Via:我给自己做了一个导航网站 | BioIT爱好者\n\n\n📢 让更多人的人制作自己的导航网站。如果你觉得本主题对你有所帮助,欢迎请作者 喝杯咖啡 >.<\n主题开源地址\nGitHub | Gitee | GitCode\n主题展示地址\nWebStack-Hugo 网址导航 | 生信网址导航\n为什么做这个网站\n之所以想着要给自己倒腾一个导航网站,主要有几个原因:\n\n购买了一个域名,且也备案成功了,总想折腾点跟它有关的事情;\n经常在公司、家里(有时候还有其他的临时场所)更换电脑,每次同步书签(或者登陆一些导航网站)需要各种登陆,麻烦。\n\n说干就干,从 WebStack 的开源项目开始,断断续续的折腾了好几天,终于把轮子造起来了。\n\n\n\n\n跟其他导航网站有什么区别\n这是 Hugo 版 WebStack 主题。可以借助 Github/Gitee Pages 或者云平台直接托管部署,无需服务器。\n本项目是基于纯静态的网址导航网站 webstack.cc 制作的 Hugo 主题,其中部分代码参考了以下几个开源项目:\n\nhttps://github.com/WebStackPage/WebStackPage.github.io\nhttps://github.com/liutongxu/liutongxu.github.io\nhttps://github.com/iplaycode/webstack-hugo\n\n总体说一下特点:\n\n采用了一直以来最喜欢的 hugo 部署方式,方便高效。\n主要的配置信息都集成到了 config.toml,一键完成各种自定义的配置。\n导航的各个信息都集成在 data/webstack.yml 文件中,方便后续增删改动。\n\n- taxonomy: 科研办公\n icon: fas fa-flask fa-lg\n list:\n - term: 生物信息\n links:\n - title: NCBI\n logo: n/ncbi.jpg\n url: https://www.ncbi.nlm.nih.gov/\n description: National Center for Biotechnology Information.\n - title: Bioconda\n logo: b/bioconda.jpg\n url: https://anaconda.org/bioconda/\n description: "Bioconda :: Anaconda.org."\n - term: 云服务器\n links:\n - title: 阿里云\n logo: a/aliyun.jpg\n url: https://www.aliyun.com/\n description: 上云就上阿里云。\n - title: 腾讯云\n logo: c/cloud-tencent.jpg\n url: https://cloud.tencent.com/\n description: 产业智变,云启未来。\n\n做了手机电脑自适应以及夜间模式。\n增加了搜索功能,以及下拉的热词选项(基于百度 API)。\n增加了一言、和风天气的 API(和风天气 API 已经官方已经不再支持,目前还没到到替代)。\n\nWindows 下安装部署\n本安装部署在 Windows 7 x64 上测试没问题,相关操作同样适用于 Windows 10,如有任何问题,欢迎留言或者微信与我联系。\n第一,下载 hugo\n下载链接:https://github.com/gohugoio/hugo/releases,在这里我们下载 hugo_0.89.4_Windows-64bit.zip。\n\n第二,解压\n我们把 hugo_0.89.4_Windows-64bit.zip 下载到 F:\\WebStack 目录下,然后解压到当前文件夹。\n解压完成后,在该目录会多出 hugo.exe、LICENSE、README.md 三个文件:\n\n第三,检测是否安装成功\n通过下面的方法,检测 hugo 是否安装成功。\n\n🏷️ 温馨提示:\nWindows 命令运行窗口中可以使用 Tab 进行命令行补全,例如你当前目录下有一个 WebStack-Hugo 目录,你在命令行窗口中输入一个 w 后按下 Tab 键,命令行就会自动出现 WebStack-Hugo!\n使用命令行补全,可以减少代码(或者文件名)的输入,方便快捷,又能减少错误!\n\n\n\n在 Windows 中使用 Win+R 打开“运行”对话框,在对话框中输入“cmd”,点击确认。\n\n\n\n在 Windows 运行窗口,先切换盘符到 F 盘,然后进入 hugo 的解压缩目录(F:\\WebStack),具体操作如下。\n\n\n在光标处输入 F:,然后按回车;\n\n\n\n我们就将盘符切换为 F 盘;\n\n\n\n接着输入 cd WebStack,回车,就进入了 F:\\WebStack 目录;使用 ls 可以看到当前目录下的文件。\n\n\n\n最后,输入 hugo.exe version,回车,如图所示,则代表安装成功。\n\n\n\n\n\n第四,下载 WebStack-Hugo\n浏览器打开 https://github.com/shenweiyan/WebStack-Hugo,点击 Code 下的 "Download ZIP",把 WebStack-hugo-main.zip 下载到刚才 hugo 解压缩的目录(F:\\WebStack)。\n\n\n第五,解压和重命名\n把 WebStack-Hugo-main.zip 解压到当前目录。\n\n\n第六,安装主题\n首先,进入 F:\\WebStack 目录;\n然后,创建一个 themes 的文件夹;\n\n接着,把解压后的 WebStack-Hugo 整个文件夹移动到 themes 中。\n\n第四,将 themes/WebStack-Hugo/exampleSite 目录下的所有文件复制到 hugo 站点根目录(即 F:\\WebStack)。\n\n第七,启动预览\n在刚才已经打开的 Windows 命令运行窗口中,使用下面的命令执行 hugo server,启动站点——Hugo 可以启动一个 Web 服务器,同时构建站点内容到内存中并在检测到文件更改后重新渲染,方便我们在开发环境实时预览对站点所做的更改。\nhugo.exe server\n\n最后,在浏览器中打开 http://127.0.0.1:1313/,即可看到生成的站点。\n\nLinux 下安装部署\n安装完本 WebStack-Hugo 主题后,将 exampleSite 目录下的文件复制到 hugo 站点根目录,根据需要把 config.toml 的一些信息改成自己的,导航的网址信息可通过 data 目录下 webstack.yml 修改。\n具体执行步骤如下:\nmkdir /home/shenweiyan/mysite\ncd /home/shenweiyan/mysite\n\n# 安装 WebStack-Hugo 主题\ngit clone https://github.com/shenweiyan/WebStack-Hugo.git themes/WebStack-Hugo\n\n# 将 exampleSite 目录下的文件复制到 hugo 站点根目录\ncd /home/shenweiyan/mysite\ncp -r themes/WebStack-Hugo/exampleSite/* ./\n\n# 启动 hugo 站点\nhugo server\n# 如果你知道你的公网 ip, 如下面的 132.76.230.31, 可以使用下面的方式执行 hugo server\nhugo server --baseUrl=132.76.230.31 --bind=0.0.0.0\n也可以参考 @jetsung 在 pull 15 所用的方法安装部署:\n# 创建项目\nmkdir navsites\ncd $_\n\n# 初始化项目\ngit init\n\n# 将 WebStack-Hugo 源下载到 themes/WebStack-Hugo 文件夹\ngit submodule add https://github.com/shenweiyan/WebStack-Hugo.git themes/WebStack-Hugo\ncp -r themes/WebStack-Hugo/exampleSite/* ./\n\n# 安装 hugo\ngo install github.com/gohugoio/hugo@latest\n\n# 本地测试\nhugo server\n\n# 生成 docs 文件夹,将并静态内容生成至此处\nhugo -D\n导出 HTML 静态资源\nWindows/Linux 下执行的 hugo server 命令将会通过热加载的方式临时启动一个 Hugo 服务器(Hugo 可以启动一个 Web 服务器,同时构建站点内容到内存中并在检测到文件更改后重新渲染,方便我们在开发环境实时预览对站点所做的更改),这个时候我们打开浏览器 http://127.0.0.1:1313/,就可以看到我们站点的样子了。\n如果我们想要把我们的站点部署到 GitHub/Gitee Pages(或者本地的服务器),我们可以:\n1. 生成静态页面内容\n可以通过下面的命令,生成(构建)静态页面内容。\nhugo -D 或者 hugo --minify\n这个命令会默认在 public/ 目录中生成您的网站,当然您可以通过改变站点配置中的 publishDir 选项来配置这个输出目录。\n\n🏷️ Hugo 小知识 - 草案、未来和过期内容\nHugo 允许您在网站内容的前言设定中设置文档的draft,publishdate甚至expirydate字段。默认情况下,Hugo 不会发布下面内容:\n\npublishdate 发布日期值设定在未来的内容;\ndraft:true 草案状态设置为真的内容;\nexpirydate 过期日期值设置为过去某事件的内容。\n\n这三个可以在本地开发和部署编译时通过对hugo和hugo server分别添加如下参数来重新设定,或者在配置文件中设定对应(不包含--)域的 boolean 值:\n\n-F, --buildFuture include content with publishdate in the future\n-D, --buildDrafts include content marked as draft\n-E, --buildExpired include expired content\n\n\n2. 部署站点\n把生成的 public/ 静态内容目录上传到 GitHub,开启 GitHub/Gitee Pages,并且绑定 cname 域名即可。\n使用说明与技巧\n这是一个开源的公益项目,你可以拿来制作自己的网址导航,也可以做与导航无关的网站。\n左导航栏图标\n左侧、顶部导航栏图标用的都是 Font Awesome 图标库 v5 版本 Free 的图标。链接如下:\n🔗 https://fontawesome.com/v5/search?o=r&m=free\n\n调整头部搜索栏\n头部搜索栏的默认位置可以通过下面的方法进行修改。\n\n直接修改 layouts/partials/content_search.html,调整对应部分的位置。\n调整默认的搜索(即点击"常用/搜索/工具 ...." 时下指箭头的指向),把对应的 id 添加到对应的 label 里面。\n\n\n\n自定义头部导航\nWebStack-Hugo 把头部的导航菜单的各个信息集成在了 data/header.yml 文件中,每个人可以根据自己的需要调整。\n- item: 首页\n icon: fa fa-home\n link: "./"\n\n- item: 作者\n icon: fa fa-book\n link: https://www.yuque.com/shenweiyan\n\n- item: 配置\n icon: fa fa-cog\n link: ""\n list:\n - name: 源码\n url: "#"\n - name: 图标\n url: "#"\n获取网站图标\nBio & IT 网址导航默认使用的是个人收集的网站图标,主要是查看网站源码、百度、谷歌等途径把对应导航的图标下载下来,这个方法比较原始繁琐,适合导航不是很多的情况。\n一为\n你也可以使用一为提供的的 Favicon 图标 API:获取网站 Favicon - 免费 API 数据接口调用服务平台。\n使用方法:\n\n获取 Favicon 图标\n\nhttps://api.iowen.cn/favicon/www.iowen.cn.png\n\n\n刷新缓存\n\nhttps://api.iowen.cn/favicon/www.iowen.cn.png?refresh=true\n\n\n将上方代码中的 www.iowen.cn 替换为你需要获取的网址域名。\n\nFavicon.im\n除了一为的 API,你也可以使用 https://favicon.im/ 来在网页中插入其他网站的 Favicon 图片,可以放大显示。\n\nFavicon Extractor\n类似网站 Favicon Downloader,代码开源。\n\n已知问题\n\n日间模式与夜间模式切换时候,头部搜索栏的背景图片切换不够流畅(个人的 js 知识有限,在 footer.html 做了一些简单的调整来实现),如果你有更好的想法,欢迎 PR 或者交流。\n\n感谢墙\n本主题的部分代码参考了以下几个开源项目,特此感谢。\n\nWebStackPage/WebStackPage.github.io\nliutongxu/liutongxu.github.io\niplaycode/webstack-hugo\n\n感谢 WebStack 的作者 Viggo 的肯定和推广宣传。\n\n感谢以下所有朋友对本主题所做出的贡献。\n@yanbeiyinhanghang\n@jetsung\n赞赏\n如果你觉得本项目对你有所帮助,欢迎请作者喝杯热咖啡 >.<\n\n反馈与交流\n最后,最重要的,秉承 WebStack 的宗旨,这是一个开源的公益项目,你可以拿来制作自己的网址导航,也可以做与导航无关的网站。\nWebStack 有非常多的魔改版本,这是其中一个。\n如果你对本主题进行了一些个性化调整,欢迎在本项目中 issues 中一起分享交流!\n如果参考本主题构建了属于你自己的网址导航,欢迎在本评论区(或源码 issues 区)留下你网站的访问链接 >.<', 'bodyHTML': '
\n

Via:我给自己做了一个导航网站 | BioIT爱好者

\n
\n
\n

📢 让更多人的人制作自己的导航网站。如果你觉得本主题对你有所帮助,欢迎请作者 喝杯咖啡 >.<

\n

主题开源地址

\n

GitHub | Gitee | GitCode

\n

主题展示地址

\n

WebStack-Hugo 网址导航 | 生信网址导航

\n

为什么做这个网站

\n

之所以想着要给自己倒腾一个导航网站,主要有几个原因:

\n
    \n
  • 购买了一个域名,且也备案成功了,总想折腾点跟它有关的事情;
  • \n
  • 经常在公司、家里(有时候还有其他的临时场所)更换电脑,每次同步书签(或者登陆一些导航网站)需要各种登陆,麻烦。
  • \n
\n

说干就干,从 WebStack 的开源项目开始,断断续续的折腾了好几天,终于把轮子造起来了。

\n

\n

\n

\n

webstack-apple

\n

跟其他导航网站有什么区别

\n

这是 Hugo 版 WebStack 主题。可以借助 Github/Gitee Pages 或者云平台直接托管部署,无需服务器。

\n

本项目是基于纯静态的网址导航网站 webstack.cc 制作的 Hugo 主题,其中部分代码参考了以下几个开源项目:

\n\n

总体说一下特点:

\n
    \n
  • 采用了一直以来最喜欢的 hugo 部署方式,方便高效。
  • \n
  • 主要的配置信息都集成到了 config.toml,一键完成各种自定义的配置。
  • \n
  • 导航的各个信息都集成在 data/webstack.yml 文件中,方便后续增删改动。
  • \n
\n
- taxonomy: 科研办公\n  icon: fas fa-flask fa-lg\n  list:\n    - term: 生物信息\n      links:\n        - title: NCBI\n          logo: n/ncbi.jpg\n          url: https://www.ncbi.nlm.nih.gov/\n          description: National Center for Biotechnology Information.\n        - title: Bioconda\n          logo: b/bioconda.jpg\n          url: https://anaconda.org/bioconda/\n          description: "Bioconda :: Anaconda.org."\n    - term: 云服务器\n      links:\n        - title: 阿里云\n          logo: a/aliyun.jpg\n          url: https://www.aliyun.com/\n          description: 上云就上阿里云。\n        - title: 腾讯云\n          logo: c/cloud-tencent.jpg\n          url: https://cloud.tencent.com/\n          description: 产业智变,云启未来。
\n
    \n
  • 做了手机电脑自适应以及夜间模式。
  • \n
  • 增加了搜索功能,以及下拉的热词选项(基于百度 API)。
  • \n
  • 增加了一言、和风天气的 API(和风天气 API 已经官方已经不再支持,目前还没到到替代)。
  • \n
\n

Windows 下安装部署

\n

本安装部署在 Windows 7 x64 上测试没问题,相关操作同样适用于 Windows 10,如有任何问题,欢迎留言或者微信与我联系。

\n

第一,下载 hugo

\n

下载链接:https://github.com/gohugoio/hugo/releases,在这里我们下载 hugo_0.89.4_Windows-64bit.zip

\n

download-hugo-windows

\n

第二,解压

\n

我们把 hugo_0.89.4_Windows-64bit.zip 下载到 F:\\WebStack 目录下,然后解压到当前文件夹。

\n

解压完成后,在该目录会多出 hugo.exeLICENSEREADME.md 三个文件:

\n

unzip hugo_0.89.4_Windows-64bit

\n

第三,检测是否安装成功

\n

通过下面的方法,检测 hugo 是否安装成功。

\n
\n

🏷️ 温馨提示:

\n

Windows 命令运行窗口中可以使用 Tab 进行命令行补全,例如你当前目录下有一个 WebStack-Hugo 目录,你在命令行窗口中输入一个 w 后按下 Tab 键,命令行就会自动出现 WebStack-Hugo!

\n

使用命令行补全,可以减少代码(或者文件名)的输入,方便快捷,又能减少错误!

\n
\n
    \n
  1. \n

    在 Windows 中使用 Win+R 打开“运行”对话框,在对话框中输入“cmd”,点击确认。

    \n

    win-r-cmd

    \n
  2. \n
  3. \n

    在 Windows 运行窗口,先切换盘符到 F 盘,然后进入 hugo 的解压缩目录(F:\\WebStack),具体操作如下。

    \n
      \n
    • \n

      在光标处输入 F:,然后按回车;

      \n

      cmd-change-dir

      \n
    • \n
    • \n

      我们就将盘符切换为 F 盘;

      \n

      cmd-f-dir

      \n
    • \n
    • \n

      接着输入 cd WebStack,回车,就进入了 F:\\WebStack 目录;使用 ls 可以看到当前目录下的文件。

      \n

      webstack-win-ls

      \n
    • \n
    • \n

      最后,输入 hugo.exe version,回车,如图所示,则代表安装成功。

      \n

      hugo-exe-version

      \n
    • \n
    \n
  4. \n
\n

第四,下载 WebStack-Hugo

\n

浏览器打开 https://github.com/shenweiyan/WebStack-Hugo,点击 Code 下的 "Download ZIP",把 WebStack-hugo-main.zip 下载到刚才 hugo 解压缩的目录(F:\\WebStack)。

\n

webstack-download-zip

\n

webstack-hugo-main-zip

\n

第五,解压和重命名

\n

WebStack-Hugo-main.zip 解压到当前目录。

\n

webstack-hugo-main-unzip
\nwebstack-hugo-main-rename

\n

第六,安装主题

\n

首先,进入 F:\\WebStack 目录;

\n

然后,创建一个 themes 的文件夹;

\n

create-themes-dir

\n

接着,把解压后的 WebStack-Hugo 整个文件夹移动到 themes 中。

\n

mv-webstack-hugo-to-themes

\n

第四,将 themes/WebStack-Hugo/exampleSite 目录下的所有文件复制到 hugo 站点根目录(即 F:\\WebStack)。

\n

cp-examplesite

\n

第七,启动预览

\n

在刚才已经打开的 Windows 命令运行窗口中,使用下面的命令执行 hugo server,启动站点——Hugo 可以启动一个 Web 服务器,同时构建站点内容到内存中并在检测到文件更改后重新渲染,方便我们在开发环境实时预览对站点所做的更改。

\n
hugo.exe server
\n

hugo-exe-server

\n

最后,在浏览器中打开 http://127.0.0.1:1313/,即可看到生成的站点。

\n

webstack-hugo-1313

\n

Linux 下安装部署

\n

安装完本 WebStack-Hugo 主题后,将 exampleSite 目录下的文件复制到 hugo 站点根目录,根据需要把 config.toml 的一些信息改成自己的,导航的网址信息可通过 data 目录下 webstack.yml 修改。

\n

具体执行步骤如下:

\n
mkdir /home/shenweiyan/mysite\ncd /home/shenweiyan/mysite\n\n# 安装 WebStack-Hugo 主题\ngit clone https://github.com/shenweiyan/WebStack-Hugo.git themes/WebStack-Hugo\n\n# 将 exampleSite 目录下的文件复制到 hugo 站点根目录\ncd /home/shenweiyan/mysite\ncp -r themes/WebStack-Hugo/exampleSite/* ./\n\n# 启动 hugo 站点\nhugo server\n# 如果你知道你的公网 ip, 如下面的 132.76.230.31, 可以使用下面的方式执行 hugo server\nhugo server --baseUrl=132.76.230.31 --bind=0.0.0.0
\n

也可以参考 @jetsungpull 15 所用的方法安装部署:

\n
# 创建项目\nmkdir navsites\ncd $_\n\n# 初始化项目\ngit init\n\n# 将 WebStack-Hugo 源下载到 themes/WebStack-Hugo 文件夹\ngit submodule add https://github.com/shenweiyan/WebStack-Hugo.git themes/WebStack-Hugo\ncp -r themes/WebStack-Hugo/exampleSite/* ./\n\n# 安装 hugo\ngo install github.com/gohugoio/hugo@latest\n\n# 本地测试\nhugo server\n\n# 生成 docs 文件夹,将并静态内容生成至此处\nhugo -D
\n

导出 HTML 静态资源

\n

Windows/Linux 下执行的 hugo server 命令将会通过热加载的方式临时启动一个 Hugo 服务器(Hugo 可以启动一个 Web 服务器,同时构建站点内容到内存中并在检测到文件更改后重新渲染,方便我们在开发环境实时预览对站点所做的更改),这个时候我们打开浏览器 http://127.0.0.1:1313/,就可以看到我们站点的样子了。

\n

如果我们想要把我们的站点部署到 GitHub/Gitee Pages(或者本地的服务器),我们可以:

\n

1. 生成静态页面内容

\n

可以通过下面的命令,生成(构建)静态页面内容。

\n
hugo -D 或者 hugo --minify
\n

这个命令会默认在 public/ 目录中生成您的网站,当然您可以通过改变站点配置中的 publishDir 选项来配置这个输出目录。

\n
\n

🏷️ Hugo 小知识 - 草案、未来和过期内容

\n

Hugo 允许您在网站内容的前言设定中设置文档的draftpublishdate甚至expirydate字段。默认情况下,Hugo 不会发布下面内容:

\n
    \n
  1. publishdate 发布日期值设定在未来的内容;
  2. \n
  3. draft:true 草案状态设置为真的内容;
  4. \n
  5. expirydate 过期日期值设置为过去某事件的内容。
  6. \n
\n

这三个可以在本地开发和部署编译时通过对hugohugo server分别添加如下参数来重新设定,或者在配置文件中设定对应(不包含--)域的 boolean 值:

\n
    \n
  1. -F, --buildFuture include content with publishdate in the future
  2. \n
  3. -D, --buildDrafts include content marked as draft
  4. \n
  5. -E, --buildExpired include expired content
  6. \n
\n
\n

2. 部署站点

\n

把生成的 public/ 静态内容目录上传到 GitHub,开启 GitHub/Gitee Pages,并且绑定 cname 域名即可。

\n

使用说明与技巧

\n

这是一个开源的公益项目,你可以拿来制作自己的网址导航,也可以做与导航无关的网站。

\n

左导航栏图标

\n

左侧、顶部导航栏图标用的都是 Font Awesome 图标库 v5 版本 Free 的图标。链接如下:

\n

🔗 https://fontawesome.com/v5/search?o=r&m=free

\n

fontawesome-v5-free

\n

调整头部搜索栏

\n

头部搜索栏的默认位置可以通过下面的方法进行修改。

\n
    \n
  1. 直接修改 layouts/partials/content_search.html,调整对应部分的位置。
  2. \n
  3. 调整默认的搜索(即点击"常用/搜索/工具 ...." 时下指箭头的指向),把对应的 id 添加到对应的 label 里面。
  4. \n
\n

set-default-search-bing
\nview-default-search-bing

\n

自定义头部导航

\n

WebStack-Hugo 把头部的导航菜单的各个信息集成在了 data/header.yml 文件中,每个人可以根据自己的需要调整。

\n
- item: 首页\n  icon: fa fa-home\n  link: "./"\n\n- item: 作者\n  icon: fa fa-book\n  link: https://www.yuque.com/shenweiyan\n\n- item: 配置\n  icon: fa fa-cog\n  link: ""\n  list:\n    - name: 源码\n      url: "#"\n    - name: 图标\n      url: "#"
\n

获取网站图标

\n

Bio & IT 网址导航默认使用的是个人收集的网站图标,主要是查看网站源码、百度、谷歌等途径把对应导航的图标下载下来,这个方法比较原始繁琐,适合导航不是很多的情况。

\n

一为

\n

你也可以使用一为提供的的 Favicon 图标 API获取网站 Favicon - 免费 API 数据接口调用服务平台

\n

使用方法:

\n
    \n
  1. 获取 Favicon 图标
  2. \n
\n
https://api.iowen.cn/favicon/www.iowen.cn.png\n
\n
    \n
  1. 刷新缓存
  2. \n
\n
https://api.iowen.cn/favicon/www.iowen.cn.png?refresh=true\n
\n
    \n
  1. 将上方代码中的 www.iowen.cn 替换为你需要获取的网址域名。
  2. \n
\n

Favicon.im

\n

除了一为的 API,你也可以使用 https://favicon.im/ 来在网页中插入其他网站的 Favicon 图片,可以放大显示。

\n

favicon-im

\n

Favicon Extractor

\n

类似网站 Favicon Downloader,代码开源

\n

favicon-extractor

\n

已知问题

\n
    \n
  1. 日间模式与夜间模式切换时候,头部搜索栏的背景图片切换不够流畅(个人的 js 知识有限,在 footer.html 做了一些简单的调整来实现),如果你有更好的想法,欢迎 PR 或者交流。
  2. \n
\n

感谢墙

\n

本主题的部分代码参考了以下几个开源项目,特此感谢。

\n\n

感谢 WebStack 的作者 Viggo 的肯定和推广宣传

\n

twitter-decohack-webstack-hugo

\n

感谢以下所有朋友对本主题所做出的贡献。
\n@yanbeiyinhanghang
\n@jetsung

\n

赞赏

\n

如果你觉得本项目对你有所帮助,欢迎请作者喝杯热咖啡 >.<

\n

donate-wecaht-aliapy

\n

反馈与交流

\n

最后,最重要的,秉承 WebStack 的宗旨,这是一个开源的公益项目,你可以拿来制作自己的网址导航,也可以做与导航无关的网站。

\n

WebStack 有非常多的魔改版本,这是其中一个。

\n

如果你对本主题进行了一些个性化调整,欢迎在本项目中 issues 中一起分享交流!

\n

如果参考本主题构建了属于你自己的网址导航,欢迎在本评论区(或源码 issues 区)留下你网站的访问链接 >.<

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '语雀'}, {'name': '1.3.25-静态网站'}]}, 'comments': {'nodes': [{'body': 'Built in 35 ms\r\nEnvironment: "development"\r\nServing pages from memory\r\nRunning in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender\r\nWeb Server is available at http://localhost:1313/ (bind address 127.0.0.1)\r\nPress Ctrl+C to stop\r\n\r\nCMD显示了这个,但是打开http://127.0.0.1:1313/ 显示的是Page Not Found\r\n\r\n我有重命名对应文件夹,但是全部放在E盘,然后下载的是hugo_0.120.4_windows-amd64 (没有)\r\n\r\n重新下载了[hugo_0.89.4_Windows-64bit.zip](https://github.com/gohugoio/hugo/releases/download/v0.89.4/hugo_0.89.4_Windows-64bit.zip) \r\n\r\n名字一模一样 问题 解决', 'author': {'login': 'CharlieLZ'}}, {'body': '非常好,感谢感谢 ', 'author': {'login': 'takayashoshi888'}}, {'body': '用hugo server启动的时候 一切都是正常的,但是hugo -D 生成静态之后左侧、顶部导航栏图标不能显示了,变成了一个方块。大佬这个怎么解决,感谢。', 'author': {'login': 'konglquan'}}, {'body': '希望安装步骤写完整一点,linux 的安装方法写详细一点。生成的网站样式错误,图片文件和样式文件加载全是404。', 'author': {'login': 'jiespring'}}, {'body': '想修改一下网格背景,但是为什么修改了custom-style.css这个文件后,网站样式没有变化啊。', 'author': {'login': 'dsshbz'}}, {'body': '这文档可以写得再清晰一点,看着有点晕啊', 'author': {'login': 'musica2016'}}]}}, {'title': '在 Linux 上给用户赋予指定目录的读写权限', 'number': 9, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/9', 'createdAt': '2023-10-23T05:16:10Z', 'lastEditedAt': '2024-08-27T02:11:37Z', 'updatedAt': '2024-08-27T02:11:37Z', 'body': '在 Linux 上指定目录的读写权限赋予用户,有两种方法可以实现这个目标:第一种是使用 ACL (访问控制列表),第二种是创建用户组来管理文件权限,下面会一一介绍。为了完成这个教程,我们将使用以下设置:\r\n\r\n- 操作系统:CentOS 7\r\n- 测试目录:/data/share\r\n- 测试用户:shenweiyan\r\n- 文件系统类型:ext4\r\n\r\n请确认所有的命令都是使用 root 用户执行的,或者使用 sudo 命令来享受与之同样的权限。让我们开始吧!下面,先使用 mkdir 命令来创建一个名为 share 的目录。\r\n\r\n```bash\r\n$ mkdir -p /data/share\r\n```\r\n\r\n## 1. ACL 权限设置\r\n\r\n**重要提示:** \r\n打算使用此方法的话,您需要确认您的 Linux 文件系统类型(如 ext3 和 ext4, NTFS, BTRFS)支持 ACL。\r\n\r\n### 1.1. 查看内核是否支持 ACL\r\n\r\n依照以下命令在您的系统中检查当前文件系统类型,并且查看内核是否支持 ACL:**\r\n\r\n```bash\r\n$ df -T | awk \'{print $1,$2,$NF}\' | grep "^/dev"\r\n$ grep -i acl /boot/config*\r\n```\r\n\r\n从下方的截屏可以看到,文件系统类型是 ext4,并且从 `CONFIG_EXT4_FS_POSIX_ACL=y` 选项可以发现内核是支持 POSIX ACL 的。\r\n![config-ext4-fs-posix-acl](https://kg.weiyan.cc/2024/08/config-ext4-fs-posix-acl.webp)\r\n\r\n### 1.2. 挂载是否使用了 ACL\r\n\r\n使用下面的命令,查看文件系统(分区)挂载时是否使用了 ACL 选项。\r\n\r\n```bash\r\n$ tune2fs -l /dev/vda1 | grep acl\r\n```\r\n\r\n![tune2fs-acl](https://kg.weiyan.cc/2024/08/tune2fs-acl.webp) \r\n通过上边的输出可以发现,默认的挂载项目中已经对 ACL 进行了支持。如果发现结果不如所愿,你可以通过以下命令对指定分区(此例中使用 /dev/sda3)开启 ACL 的支持)。\r\n\r\n```bash\r\n$ mount -o remount,acl /\r\n$ tune2fs -o acl /dev/sda3\r\n```\r\n\r\n### 1.3. 设置 ACL 权限\r\n\r\n```bash\r\nsetfacl -m m:rx 文件名 # 给 mask 的权限为 r-x ,使用 "m:rx"格式 \r\n\r\nsetfacl -m u:用户名:权限 -R 目录名 # 递归 ACL 权限(针对目录现有的文件设置 ACL) \r\n```\r\n\r\n例如,指定目录 `share` 的读写权限分配给名为 `shenweiyan` 的用户了,依照以下命令执行即可。\r\n\r\n```bash\r\n# 检查目录默认的 ACL 设置(Check the default ACL settings for the directory)\r\n$ getfacl /data/share\r\n\r\n# 指定用户读写权限(Give rw access to user shenweiyan)\r\n# 对于目录必须增加 x (执行)权限, 否则无法进入目录\r\n$ setfacl -m user:shenweiyan:rwx /data/share\r\n\r\n# 再次检查目录 ACL 设置(Check new ACL settings for the directory)\r\n$ getfacl /data/share\r\n```\r\n\r\n![setfacl-m-user](https://kg.weiyan.cc/2024/08/setfacl-m-user.webp) \r\n在上方的截屏中,通过输出结果的第二行 getfacl 命令可以发现,用户 shenweiyan 已经成功的被赋予了 /data/share 目录的读写权限。\r\n\r\n如果想要获取 ACL 列表的更多信息。请参考:\r\n\r\n- [如何使用访问控制列表(ACL)为用户/组设置磁盘配额](http://www.tecmint.com/set-access-control-lists-acls-and-disk-quotas-for-users-groups/)\r\n- [如何使用访问控制列表(ACL)挂载网络共享](http://www.tecmint.com/rhcsa-exam-configure-acls-and-mount-nfs-samba-shares/)\r\n\r\n### 1.4. 删除 ACL 权限\r\n\r\n如果用户名(组名)已经删除,可以使用 UID(GID)进行删除。\r\n\r\n```bash\r\nsetfacl -x u:用户名 文件名 # 删除指定用户的 ACL 权限\r\nsetfacl -x g:组名 文件名 # 删除指定组的 ACL 权限 \r\nsetfacl -b 文件名 # 删除文件下所有的 ACL 权限 \r\n```\r\n\r\n## 2. 用户组权限设置\r\n\r\n### 2.1. 变更属组\r\n\r\n如果用户已经拥有了默认的用户组(通常组名与用户名相同),就可以简单的通过变更文件夹的所属用户组来完成。\r\n\r\n```python\r\n$ chgrp shenweiyan /data/share\r\n```\r\n\r\n另外,我们也可以通过以下方法为多个用户(需要赋予指定目录读写权限的)新建一个用户组。如此一来,也就创建了一个共享目录。\r\n\r\n```python\r\n$ groupadd dbshare\r\n```\r\n\r\n### 2.2. 把用户添加到属组 \r\n\r\n接下来将用户 `shenweiyan` 添加到 `dbshare` 组中:\r\n\r\n```python\r\n# add user to projects\r\n$ usermod -aG dbshare shenweiyan\r\n\r\n# check users groups\r\n$ groups tecmint\r\n```\r\n\r\n### 2.3. 变更属组\r\n\r\n将目录的所属用户组变更为 `dbshare`:\r\n\r\n```python\r\n$ chgrp projects /data/share\r\n```\r\n\r\n### 2.4. 设置组员权限\r\n\r\n现在,给组成员设置读写权限。\r\n\r\n```bash\r\n$ chmod -R 0760 /data/share\r\n\r\n# check new permissions\r\n$ ls -l /data/share\r\n```\r\n\r\nok,在 Linux 上给用户赋予指定目录的读写权限就介绍到这里 !\r\n\r\n## 3. 参考资料\r\n\r\n- 高延斌,《[Linux ACL 体验](https://www.ibm.com/developerworks/cn/linux/l-acl/index.html)》,IBM Developer\r\n- Mr-Ping,《在 Linux 上给用户赋予指定目录的读写权限》,Linux 中国\r\n', 'bodyText': '在 Linux 上指定目录的读写权限赋予用户,有两种方法可以实现这个目标:第一种是使用 ACL (访问控制列表),第二种是创建用户组来管理文件权限,下面会一一介绍。为了完成这个教程,我们将使用以下设置:\n\n操作系统:CentOS 7\n测试目录:/data/share\n测试用户:shenweiyan\n文件系统类型:ext4\n\n请确认所有的命令都是使用 root 用户执行的,或者使用 sudo 命令来享受与之同样的权限。让我们开始吧!下面,先使用 mkdir 命令来创建一个名为 share 的目录。\n$ mkdir -p /data/share\n1. ACL 权限设置\n重要提示:\n打算使用此方法的话,您需要确认您的 Linux 文件系统类型(如 ext3 和 ext4, NTFS, BTRFS)支持 ACL。\n1.1. 查看内核是否支持 ACL\n依照以下命令在您的系统中检查当前文件系统类型,并且查看内核是否支持 ACL:**\n$ df -T | awk \'{print $1,$2,$NF}\' | grep "^/dev"\n$ grep -i acl /boot/config*\n从下方的截屏可以看到,文件系统类型是 ext4,并且从 CONFIG_EXT4_FS_POSIX_ACL=y 选项可以发现内核是支持 POSIX ACL 的。\n\n1.2. 挂载是否使用了 ACL\n使用下面的命令,查看文件系统(分区)挂载时是否使用了 ACL 选项。\n$ tune2fs -l /dev/vda1 | grep acl\n\n通过上边的输出可以发现,默认的挂载项目中已经对 ACL 进行了支持。如果发现结果不如所愿,你可以通过以下命令对指定分区(此例中使用 /dev/sda3)开启 ACL 的支持)。\n$ mount -o remount,acl /\n$ tune2fs -o acl /dev/sda3\n1.3. 设置 ACL 权限\nsetfacl -m m:rx 文件名 # 给 mask 的权限为 r-x ,使用 "m:rx"格式 \n\nsetfacl -m u:用户名:权限 -R 目录名 # 递归 ACL 权限(针对目录现有的文件设置 ACL) \n例如,指定目录 share 的读写权限分配给名为 shenweiyan 的用户了,依照以下命令执行即可。\n# 检查目录默认的 ACL 设置(Check the default ACL settings for the directory)\n$ getfacl /data/share\n\n# 指定用户读写权限(Give rw access to user shenweiyan)\n# 对于目录必须增加 x (执行)权限, 否则无法进入目录\n$ setfacl -m user:shenweiyan:rwx /data/share\n\n# 再次检查目录 ACL 设置(Check new ACL settings for the directory)\n$ getfacl /data/share\n\n在上方的截屏中,通过输出结果的第二行 getfacl 命令可以发现,用户 shenweiyan 已经成功的被赋予了 /data/share 目录的读写权限。\n如果想要获取 ACL 列表的更多信息。请参考:\n\n如何使用访问控制列表(ACL)为用户/组设置磁盘配额\n如何使用访问控制列表(ACL)挂载网络共享\n\n1.4. 删除 ACL 权限\n如果用户名(组名)已经删除,可以使用 UID(GID)进行删除。\nsetfacl -x u:用户名 文件名 # 删除指定用户的 ACL 权限\nsetfacl -x g:组名 文件名 # 删除指定组的 ACL 权限 \nsetfacl -b 文件名 # 删除文件下所有的 ACL 权限 \n2. 用户组权限设置\n2.1. 变更属组\n如果用户已经拥有了默认的用户组(通常组名与用户名相同),就可以简单的通过变更文件夹的所属用户组来完成。\n$ chgrp shenweiyan /data/share\n另外,我们也可以通过以下方法为多个用户(需要赋予指定目录读写权限的)新建一个用户组。如此一来,也就创建了一个共享目录。\n$ groupadd dbshare\n2.2. 把用户添加到属组\n接下来将用户 shenweiyan 添加到 dbshare 组中:\n# add user to projects\n$ usermod -aG dbshare shenweiyan\n\n# check users groups\n$ groups tecmint\n2.3. 变更属组\n将目录的所属用户组变更为 dbshare:\n$ chgrp projects /data/share\n2.4. 设置组员权限\n现在,给组成员设置读写权限。\n$ chmod -R 0760 /data/share\n\n# check new permissions\n$ ls -l /data/share\nok,在 Linux 上给用户赋予指定目录的读写权限就介绍到这里 !\n3. 参考资料\n\n高延斌,《Linux ACL 体验》,IBM Developer\nMr-Ping,《在 Linux 上给用户赋予指定目录的读写权限》,Linux 中国', 'bodyHTML': '

在 Linux 上指定目录的读写权限赋予用户,有两种方法可以实现这个目标:第一种是使用 ACL (访问控制列表),第二种是创建用户组来管理文件权限,下面会一一介绍。为了完成这个教程,我们将使用以下设置:

\n
    \n
  • 操作系统:CentOS 7
  • \n
  • 测试目录:/data/share
  • \n
  • 测试用户:shenweiyan
  • \n
  • 文件系统类型:ext4
  • \n
\n

请确认所有的命令都是使用 root 用户执行的,或者使用 sudo 命令来享受与之同样的权限。让我们开始吧!下面,先使用 mkdir 命令来创建一个名为 share 的目录。

\n
$ mkdir -p /data/share
\n

1. ACL 权限设置

\n

重要提示:
\n打算使用此方法的话,您需要确认您的 Linux 文件系统类型(如 ext3 和 ext4, NTFS, BTRFS)支持 ACL。

\n

1.1. 查看内核是否支持 ACL

\n

依照以下命令在您的系统中检查当前文件系统类型,并且查看内核是否支持 ACL:**

\n
$ df -T | awk \'{print $1,$2,$NF}\' | grep "^/dev"\n$ grep -i acl /boot/config*
\n

从下方的截屏可以看到,文件系统类型是 ext4,并且从 CONFIG_EXT4_FS_POSIX_ACL=y 选项可以发现内核是支持 POSIX ACL 的。
\nconfig-ext4-fs-posix-acl

\n

1.2. 挂载是否使用了 ACL

\n

使用下面的命令,查看文件系统(分区)挂载时是否使用了 ACL 选项。

\n
$ tune2fs -l /dev/vda1 | grep acl
\n

tune2fs-acl
\n通过上边的输出可以发现,默认的挂载项目中已经对 ACL 进行了支持。如果发现结果不如所愿,你可以通过以下命令对指定分区(此例中使用 /dev/sda3)开启 ACL 的支持)。

\n
$ mount -o remount,acl /\n$ tune2fs -o acl /dev/sda3
\n

1.3. 设置 ACL 权限

\n
setfacl -m m:rx 文件名    # 给 mask 的权限为 r-x ,使用 "m:rx"格式 \n\nsetfacl -m u:用户名:权限 -R 目录名   # 递归 ACL 权限(针对目录现有的文件设置 ACL) 
\n

例如,指定目录 share 的读写权限分配给名为 shenweiyan 的用户了,依照以下命令执行即可。

\n
# 检查目录默认的 ACL 设置(Check the default ACL settings for the directory)\n$ getfacl /data/share\n\n# 指定用户读写权限(Give rw access to user shenweiyan)\n# 对于目录必须增加 x (执行)权限, 否则无法进入目录\n$ setfacl -m user:shenweiyan:rwx /data/share\n\n# 再次检查目录 ACL 设置(Check new ACL settings for the directory)\n$ getfacl /data/share
\n

setfacl-m-user
\n在上方的截屏中,通过输出结果的第二行 getfacl 命令可以发现,用户 shenweiyan 已经成功的被赋予了 /data/share 目录的读写权限。

\n

如果想要获取 ACL 列表的更多信息。请参考:

\n\n

1.4. 删除 ACL 权限

\n

如果用户名(组名)已经删除,可以使用 UID(GID)进行删除。

\n
setfacl -x u:用户名 文件名     # 删除指定用户的 ACL 权限\nsetfacl -x g:组名   文件名     # 删除指定组的 ACL 权限 \nsetfacl -b 文件名              # 删除文件下所有的 ACL 权限 
\n

2. 用户组权限设置

\n

2.1. 变更属组

\n

如果用户已经拥有了默认的用户组(通常组名与用户名相同),就可以简单的通过变更文件夹的所属用户组来完成。

\n
$ chgrp shenweiyan /data/share
\n

另外,我们也可以通过以下方法为多个用户(需要赋予指定目录读写权限的)新建一个用户组。如此一来,也就创建了一个共享目录。

\n
$ groupadd dbshare
\n

2.2. 把用户添加到属组

\n

接下来将用户 shenweiyan 添加到 dbshare 组中:

\n
# add user to projects\n$ usermod -aG dbshare shenweiyan\n\n# check users groups\n$ groups tecmint
\n

2.3. 变更属组

\n

将目录的所属用户组变更为 dbshare

\n
$ chgrp projects /data/share
\n

2.4. 设置组员权限

\n

现在,给组成员设置读写权限。

\n
$ chmod -R 0760 /data/share\n\n# check new permissions\n$ ls -l /data/share
\n

ok,在 Linux 上给用户赋予指定目录的读写权限就介绍到这里 !

\n

3. 参考资料

\n
    \n
  • 高延斌,《Linux ACL 体验》,IBM Developer
  • \n
  • Mr-Ping,《在 Linux 上给用户赋予指定目录的读写权限》,Linux 中国
  • \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '1.3.17-服务器配置使用'}]}, 'comments': {'nodes': []}}, {'title': '个人域名跳转至语雀个人主页', 'number': 8, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/8', 'createdAt': '2023-10-23T01:51:34Z', 'lastEditedAt': '2023-10-23T01:54:54Z', 'updatedAt': '2024-01-03T07:58:05Z', 'body': '> 📢 域名 [https://weiyan.cc](https://weiyan.cc) 就是基于本文章中的 "**[无服务器](#pG3U6)**" 步骤实现的个人域名跳转至语雀个人主页!因此,本篇文档你也可以通过以下的链接访问:[https://weiyan.cc/cookbook/301-redirects](https://weiyan.cc/cookbook/301-redirects)!\r\n\r\n语雀的个人使用目前是不支持自定义域名的,虽然空间的使用可以自定义二级域名,如:[weiyan.yuque.com](https://weiyan.yuque.com/),但是空间知识库必须要先登录,不方便其他人查看,尤其是对于没有注册语雀的用户。\r\n\r\n现在的情况是,我有一个已经备案的个人域名 `www.example.com`,现在我想:\r\n\r\n- 让所有 `www.example.com` 的访问地址都跳转到 ,比如 `https://www.example.com/cookbook` 跳转到 。\r\n- `www.example.com` 的访问地址跳转同时支持 http/https。\r\n- `example.com/www.example.com` 同时实现以上跳转。\r\n\r\n反正就一句话,让下面的链接都跳转到 :\r\n\r\n- \r\n- \r\n- \r\n- \r\n\r\n下面简单记录一下具体的实现过程。\r\n\r\n## 背景知识\r\n\r\n**显性 URL 转发:** 用的是 301 重定向技术,效果为浏览器地址栏输入 [http://a.com](http://a.com/) 回车,打开网站内容是目标地址 的网站内容,且地址栏显示目标地址 [http://cloud.baidu.com/](http://cloud.baidu.com/) 。\r\n\r\n**隐性 URL 转发:** 用的是 iframe 框架技术、非重定向技术,效果为浏览器地址栏输入 [http://a.com](http://a.com/) 回车,打开网站内容是目标地址 的网站内容,但地址栏显示当前地址 [http://a.com](http://a.com/) 。\r\n\r\n**301 重定向是什么?**\r\n\r\n301 重定向表示网页由一个地址永久地移动到了另外一个地址。这里中的 301 是被重定向网页的 HTTP 状态代码。\r\n\r\n**例如:** [blog.ahrefs.com](https://blog.ahrefs.com/) 重定向到了 [ahrefs.com/blog](https://ahrefs.com/blog)。\r\n\r\n简单来说,301 重定向是在告诉浏览器:“这个页面已经永久迁移了。这个是新的地址,我们不打算把它移回去啦。”这时,浏览器会回复:“没问题!我现在(开始)就把用户引向这里!”\r\n\r\n这就是为什么访问 blog.ahrefs.com 已经不可能了。你最后会去到的网页是 ahrefs.com/blog。\r\n\r\n## 前提条件\r\n\r\n前提条件可以分为**有服务器**和**无服务器**两种情况,下面具体说一下。\r\n\r\n1. 有服务器(可以考虑腾讯云或者阿里云的轻量云服务器,双十一优惠价一年也就几十块);\r\n\r\n - 阿里云轻量云服务器:[购买链接](https://www.aliyun.com/activity/1111?userCode=mx65q35j)\r\n - 腾讯云轻量云服务器:[购买链接](https://curl.qcloud.com/0Sy0R0AX)\r\n - 域名(域名需要已经完成备案);\r\n - SSL 证书(可以使用阿里云或者腾讯云的免费域名证书);\r\n\r\n2. 无服务器\r\n - 可以考虑使用 [Cloudflare Page Rules](https://support.cloudflare.com/hc/zh-cn/articles/218411427)(页面规则);当然,其他的平台也可以;\r\n - 域名(有些域名可以不用备案);\r\n - SSL 证书(如果你用的是 [Cloudflare Page Rules](https://support.cloudflare.com/hc/zh-cn/articles/218411427),可以不用 SSL 证书 )。\r\n\r\n## 操作步骤:有服务器\r\n\r\n本操作以 **ncbix.com** 域名为示例。\r\n\r\n### 1. 域名解析\r\n\r\n在你的域名供应商后台点击“添加记录”,分别输入 www 和 @,记录类型“A”,记录值就是你虚拟主机或 VPS 服务器的 IP 地址,最后保存。以 DNSPOD 为例。\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FqvWUx6cyUz-O8d1avOdFZ1aDIWF.png)\r\n\r\n### 2. SSL 证书\r\n\r\n申请免费证书,具体操作可以自行百度。以腾讯云为例:。\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/Fo4XBIRStXxx27kvjKULIjHazdJ9.png)\r\n根据截图,一步步点击操作。申请完成后,把证书下载并上传到你的服务器。\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FqamrO4EBSQuO6wsJ28y8g-AH63E.png)\r\n\r\n### 3. 安装 Nginx\r\n\r\n可以直接使用 **yum/apt** 的方式直接安装;源码方式的安装,参考:《[CentOS 7 下编译安装 Nginx · 语雀](https://www.yuque.com/shenweiyan/cookbook/centos-install-nginx)》。\r\n\r\n```bash\r\n# Debian/Ubuntu\r\napt update\r\napt install nginx\r\n\r\n# CentOS/RHEL\r\nyum install nginx\r\n```\r\n\r\n### 4. 配置 Nginx\r\n\r\n通过 **yum/apt** 安装的 Nginx 默认的置文件在 **/etc/nginx/nginx.conf**,编辑该文件。\r\n\r\n```nginx\r\nhttp {\r\n ##\r\n # Basic Settings\r\n ##\r\n ......\r\n\r\n ##\r\n # Virtual Host Configs\r\n ##\r\nserver {\r\n listen 80;\r\n listen 443 ssl;\r\n server_name ncbix.com www.ncbix.com;\r\n ssl_certificate /etc/nginx/ssl/nginx/www.ncbix.com_bundle.crt;\r\n ssl_certificate_key /etc/nginx/ssl/nginx/www.ncbix.com.key;\r\n index index.php index.html index.htm;\r\n\r\n if ( $scheme = "http" ) {\r\n return 301 https://www.yuque.com/shenweiyan$request_uri; #确保跳转到新域名HTTPS如果没有HTTPS可以去掉\r\n }\r\n location / {\r\n rewrite /.* https://www.yuque.com/shenweiyan$uri redirect; #跳转到新域名并重写为新域名\r\n }\r\n }\r\n\r\ninclude /etc/nginx/conf.d/*.conf;\r\n include /etc/nginx/sites-enabled/*;\r\n}\r\n```\r\n\r\n### 5. 重启 Nginx\r\n\r\n最后,通过下面的命令重启 Nginx 服务即可。\r\n\r\n```bash\r\nservice nginx restart\r\n```\r\n\r\n## 操作步骤:无服务器\r\n\r\n我们以 [Cloudflare Page Rules](https://support.cloudflare.com/hc/zh-cn/articles/218411427) 为例,说明一下具体怎么操作。\r\n\r\n### 1. Cloudflare 中添加站点\r\n\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/Fjd2wS9yVs0ZiBBalZQVOuPQHbU1.png)\r\n\r\n添加完站点后,可以选择 **Free 计划**,然后点击继续:\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FumaUELUaIJnv9s0Q4paKUDIAWTL.png)\r\n\r\n点击继续后,Cloudflare 会自动扫描你对应域名的一些解析记录:\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FtQZKAyQd_6dd5d7A_ZLCVp4NUEg.png)\r\n\r\n我们可以直接选择 **"继续"**。\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/Fvkt0gHVP7lmiqapWf3pM7Zx4YwN.png)\r\n\r\n### 2. 修改域名 DNS\r\n\r\n首先,我的域名是在腾讯云注册的,可以去腾讯云控制台 **"我的域名"** 中直接修改 DNS:\r\n\r\n```\r\n# 添加 Cloudflare 名称服务器\r\nimani.ns.cloudflare.com\r\ncaroline.dnspod.net\r\n```\r\n\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FlKyYHHLGHwD9IPKYvLtPorghBpr.png)\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FmRwodrlbkBt6SkX7RsG2ec1iruc.png)\r\n\r\n### 3. 完成 Cloudflare 添加站点\r\n\r\n可以把后面快速指南的这几个配置都勾选。\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FtULJ4uM_TuPjPkkMtdXAhxpyDes.png)\r\n\r\n等待几分钟就可以看到你的域名站点已经添加到 Cloudflare 上了!\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/Fk8Hv5dkW8kHd1IorhNfT427RliQ.png)\r\n\r\n### 4. 设置 DNS 记录\r\n\r\n> The first thing you will need is a DNS record for **@**, **www** and any other subdomains you want to redirect, set to ![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FjjhP041Zj-aZVPAHpQ-YnHIzMA6.png). This can point to any IP address as the redirection page rule will execute first. I would recommend pointing them to 192.0.2.1 , a dummy IP.\r\n>\r\n> From:\r\n\r\n在配置 Cloudflare 站点的页面规则前,你需要把该域名的 **@**,**www** 或者其他你想要进行重定向的子域名添加到 DNS 记录中,这个记录的值可以指向任何 IP 地址,因为重定向页面规则将首先执行。我建议将它们指向 192.0.2.1 ,一个虚拟 IP。\r\n\r\n在这里,我们以 **@** 和 **note** 子域名为例,添加 DNS 记录,先让它们指向一个虚拟 IP。\r\n![images](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/Fk08ydFuPukTv88AAa0V27T4xTBh.png "以 ncbix.com 和 note.ncbix.com 为例,均重定向到 https://www.yuque.com/shenweiyan 页面")\r\n\r\n### 5. 配置 Cloudflare 站点页面规则\r\n\r\n首先,在 Cloudflare 的主页上点击对应的站点,选择 **"页面规则"**,点击。\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FqolXaSzUdkgtKo66yRC3xRkV7mv.png)\r\n\r\n点击 **"创建页面规则"**:\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FnF2bk6hzYvulCtXdLSQSUiV1Z44.png)\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/Fp5DSLxKInn25a591hjYjDNpUeRn.png)\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FiFuRSizKlmkmJ5LxiBfkIGreBdm.png)\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FtNPR2rLIFDKMYz3N8gqkLBcQFnG.png)\r\n\r\n#### 什么是页面规则?\r\n\r\n> 页面规则为 Cloudflare 设置提供基于 URL 的粒度控制。关于页面规则需要了解的最重要事情是,针对一个 URL 仅触发一个页面规则,因此一定要按照优先级顺序对页面规则进行排序并将最具体的页面规则放在顶部。\r\n\r\n##### 页面规则中允许哪些模式?\r\n\r\n> 如果使用的是转发页面规则,则可以将这些通配符映射到变量。在转发 URL 中,可以按照从左到右的顺序指定与原始 URL 中的通配符相匹配的 $1、$2,以此类推。\r\n>\r\n> 例如,可以将 `http://.example.com/` 转发到 `http://$2.example.com/$1.jpg`。此规则将与 相匹配,这最终将转发到 。\r\n\r\n##### 一些有用的提示:\r\n\r\n> 1. 如果要同时匹配 http 和 https,只需编写 example.com 即可。无需编写 example.com。\r\n> 2. 如果要匹配域中的每个页面,则需要编写 example.com/,仅编写 example.com 是不够的。\r\n> 3. 请参阅 [了解和配置 Cloudflare 页面规则](https://support.cloudflare.com/hc/articles/218411427) 了解有关页面规则模式的更多详细信息。\r\n\r\n### 6. 配置 SSL(不必要)\r\n\r\n**📢 Update 2022.09.05:这一步不是必要的,这里仅供参考!**\r\n\r\n1. 申请 [www.example.com](http://www.example.com) 域名的 SSL 证书;\r\n2. 把 DNS 验证域名的记录添加到 Cloudfare 的 DNS 中;\r\n\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FiEmXujpQKK0j0p2GxzaOgTC3xwN.png)\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FnOHAmNIAcEmwBD_fv3eIUBzxmiB.png)\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FtxcA4iXJhT029vkw35EVkDN-2QG.png)\r\n\r\n**注意:**\r\n![image.png](https://shub-1251708715.cos.ap-guangzhou.myqcloud.com/elog-cookbook-img/FgrIb03h7Inot6k7fa1BHGH4G3HO.png)\r\n\r\n## 参考资料\r\n\r\n1. [nginx 实现两个域名之间跳转配置 - SegmentFault 思否](https://segmentfault.com/q/1010000015157572)\r\n2. [智能云解析 DNS - 通过 Nginx 实现 URL 转发 | 百度智能云文档](https://cloud.baidu.com/doc/DNS/s/ukq4w1pji)\r\n3. [SEO 的 301 重定向:你需要知道的一切](https://ahrefs.com/blog/zh/301-redirects/)\r\n', 'bodyText': '📢 域名 https://weiyan.cc 就是基于本文章中的 "无服务器" 步骤实现的个人域名跳转至语雀个人主页!因此,本篇文档你也可以通过以下的链接访问:https://weiyan.cc/cookbook/301-redirects!\n\n语雀的个人使用目前是不支持自定义域名的,虽然空间的使用可以自定义二级域名,如:weiyan.yuque.com,但是空间知识库必须要先登录,不方便其他人查看,尤其是对于没有注册语雀的用户。\n现在的情况是,我有一个已经备案的个人域名 www.example.com,现在我想:\n\n让所有 www.example.com 的访问地址都跳转到 https://www.yuque.com/shenweiyan,比如 https://www.example.com/cookbook 跳转到 https://www.yuque.com/shenweiyan/cookbook。\nwww.example.com 的访问地址跳转同时支持 http/https。\nexample.com/www.example.com 同时实现以上跳转。\n\n反正就一句话,让下面的链接都跳转到 https://www.yuque.com/shenweiyan:\n\nhttp://example.com\nhttp://www.example.com\nhttps://example.com\nhttps://www.example.com\n\n下面简单记录一下具体的实现过程。\n背景知识\n显性 URL 转发: 用的是 301 重定向技术,效果为浏览器地址栏输入 http://a.com 回车,打开网站内容是目标地址 http://cloud.baidu.com/ 的网站内容,且地址栏显示目标地址 http://cloud.baidu.com/ 。\n隐性 URL 转发: 用的是 iframe 框架技术、非重定向技术,效果为浏览器地址栏输入 http://a.com 回车,打开网站内容是目标地址 http://cloud.baidu.com/ 的网站内容,但地址栏显示当前地址 http://a.com 。\n301 重定向是什么?\n301 重定向表示网页由一个地址永久地移动到了另外一个地址。这里中的 301 是被重定向网页的 HTTP 状态代码。\n例如: blog.ahrefs.com 重定向到了 ahrefs.com/blog。\n简单来说,301 重定向是在告诉浏览器:“这个页面已经永久迁移了。这个是新的地址,我们不打算把它移回去啦。”这时,浏览器会回复:“没问题!我现在(开始)就把用户引向这里!”\n这就是为什么访问 blog.ahrefs.com 已经不可能了。你最后会去到的网页是 ahrefs.com/blog。\n前提条件\n前提条件可以分为有服务器和无服务器两种情况,下面具体说一下。\n\n\n有服务器(可以考虑腾讯云或者阿里云的轻量云服务器,双十一优惠价一年也就几十块);\n\n阿里云轻量云服务器:购买链接\n腾讯云轻量云服务器:购买链接\n域名(域名需要已经完成备案);\nSSL 证书(可以使用阿里云或者腾讯云的免费域名证书);\n\n\n\n无服务器\n\n可以考虑使用 Cloudflare Page Rules(页面规则);当然,其他的平台也可以;\n域名(有些域名可以不用备案);\nSSL 证书(如果你用的是 Cloudflare Page Rules,可以不用 SSL 证书 )。\n\n\n\n操作步骤:有服务器\n本操作以 ncbix.com 域名为示例。\n1. 域名解析\n在你的域名供应商后台点击“添加记录”,分别输入 www 和 @,记录类型“A”,记录值就是你虚拟主机或 VPS 服务器的 IP 地址,最后保存。以 DNSPOD 为例。\n\n2. SSL 证书\n申请免费证书,具体操作可以自行百度。以腾讯云为例:https://console.cloud.tencent.com/ssl。\n\n根据截图,一步步点击操作。申请完成后,把证书下载并上传到你的服务器。\n\n3. 安装 Nginx\n可以直接使用 yum/apt 的方式直接安装;源码方式的安装,参考:《CentOS 7 下编译安装 Nginx · 语雀》。\n# Debian/Ubuntu\napt update\napt install nginx\n\n# CentOS/RHEL\nyum install nginx\n4. 配置 Nginx\n通过 yum/apt 安装的 Nginx 默认的置文件在 /etc/nginx/nginx.conf,编辑该文件。\nhttp {\n ##\n # Basic Settings\n ##\n ......\n\n ##\n # Virtual Host Configs\n ##\nserver {\n listen 80;\n listen 443 ssl;\n server_name ncbix.com www.ncbix.com;\n ssl_certificate /etc/nginx/ssl/nginx/www.ncbix.com_bundle.crt;\n ssl_certificate_key /etc/nginx/ssl/nginx/www.ncbix.com.key;\n index index.php index.html index.htm;\n\n if ( $scheme = "http" ) {\n return 301 https://www.yuque.com/shenweiyan$request_uri; #确保跳转到新域名HTTPS如果没有HTTPS可以去掉\n }\n location / {\n rewrite /.* https://www.yuque.com/shenweiyan$uri redirect; #跳转到新域名并重写为新域名\n }\n }\n\ninclude /etc/nginx/conf.d/*.conf;\n include /etc/nginx/sites-enabled/*;\n}\n5. 重启 Nginx\n最后,通过下面的命令重启 Nginx 服务即可。\nservice nginx restart\n操作步骤:无服务器\n我们以 Cloudflare Page Rules 为例,说明一下具体怎么操作。\n1. Cloudflare 中添加站点\n\n添加完站点后,可以选择 Free 计划,然后点击继续:\n\n点击继续后,Cloudflare 会自动扫描你对应域名的一些解析记录:\n\n我们可以直接选择 "继续"。\n\n2. 修改域名 DNS\n首先,我的域名是在腾讯云注册的,可以去腾讯云控制台 "我的域名" 中直接修改 DNS:\n# 添加 Cloudflare 名称服务器\nimani.ns.cloudflare.com\ncaroline.dnspod.net\n\n\n\n3. 完成 Cloudflare 添加站点\n可以把后面快速指南的这几个配置都勾选。\n\n等待几分钟就可以看到你的域名站点已经添加到 Cloudflare 上了!\n\n4. 设置 DNS 记录\n\nThe first thing you will need is a DNS record for @, www and any other subdomains you want to redirect, set to . This can point to any IP address as the redirection page rule will execute first. I would recommend pointing them to 192.0.2.1 , a dummy IP.\nFrom:https://community.cloudflare.com/t/redirecting-one-domain-to-another/81960\n\n在配置 Cloudflare 站点的页面规则前,你需要把该域名的 @,www 或者其他你想要进行重定向的子域名添加到 DNS 记录中,这个记录的值可以指向任何 IP 地址,因为重定向页面规则将首先执行。我建议将它们指向 192.0.2.1 ,一个虚拟 IP。\n在这里,我们以 @ 和 note 子域名为例,添加 DNS 记录,先让它们指向一个虚拟 IP。\n\n5. 配置 Cloudflare 站点页面规则\n首先,在 Cloudflare 的主页上点击对应的站点,选择 "页面规则",点击。\n\n点击 "创建页面规则":\n\n\n\n\n什么是页面规则?\n\n页面规则为 Cloudflare 设置提供基于 URL 的粒度控制。关于页面规则需要了解的最重要事情是,针对一个 URL 仅触发一个页面规则,因此一定要按照优先级顺序对页面规则进行排序并将最具体的页面规则放在顶部。\n\n页面规则中允许哪些模式?\n\n如果使用的是转发页面规则,则可以将这些通配符映射到变量。在转发 URL 中,可以按照从左到右的顺序指定与原始 URL 中的通配符相匹配的 $1、$2,以此类推。\n例如,可以将 http://.example.com/ 转发到 http://$2.example.com/$1.jpg。此规则将与 http://cloud.example.com/flare 相匹配,这最终将转发到 http://flare.example.com/cloud.jpg。\n\n一些有用的提示:\n\n\n如果要同时匹配 http 和 https,只需编写 example.com 即可。无需编写 example.com。\n如果要匹配域中的每个页面,则需要编写 example.com/,仅编写 example.com 是不够的。\n请参阅 了解和配置 Cloudflare 页面规则 了解有关页面规则模式的更多详细信息。\n\n\n6. 配置 SSL(不必要)\n📢 Update 2022.09.05:这一步不是必要的,这里仅供参考!\n\n申请 www.example.com 域名的 SSL 证书;\n把 DNS 验证域名的记录添加到 Cloudfare 的 DNS 中;\n\n\n\n\n注意:\n\n参考资料\n\nnginx 实现两个域名之间跳转配置 - SegmentFault 思否\n智能云解析 DNS - 通过 Nginx 实现 URL 转发 | 百度智能云文档\nSEO 的 301 重定向:你需要知道的一切', 'bodyHTML': '
\n

📢 域名 https://weiyan.cc 就是基于本文章中的 "无服务器" 步骤实现的个人域名跳转至语雀个人主页!因此,本篇文档你也可以通过以下的链接访问:https://weiyan.cc/cookbook/301-redirects

\n
\n

语雀的个人使用目前是不支持自定义域名的,虽然空间的使用可以自定义二级域名,如:weiyan.yuque.com,但是空间知识库必须要先登录,不方便其他人查看,尤其是对于没有注册语雀的用户。

\n

现在的情况是,我有一个已经备案的个人域名 www.example.com,现在我想:

\n\n

反正就一句话,让下面的链接都跳转到 https://www.yuque.com/shenweiyan

\n\n

下面简单记录一下具体的实现过程。

\n

背景知识

\n

显性 URL 转发: 用的是 301 重定向技术,效果为浏览器地址栏输入 http://a.com 回车,打开网站内容是目标地址 http://cloud.baidu.com/ 的网站内容,且地址栏显示目标地址 http://cloud.baidu.com/

\n

隐性 URL 转发: 用的是 iframe 框架技术、非重定向技术,效果为浏览器地址栏输入 http://a.com 回车,打开网站内容是目标地址 http://cloud.baidu.com/ 的网站内容,但地址栏显示当前地址 http://a.com

\n

301 重定向是什么?

\n

301 重定向表示网页由一个地址永久地移动到了另外一个地址。这里中的 301 是被重定向网页的 HTTP 状态代码。

\n

例如: blog.ahrefs.com 重定向到了 ahrefs.com/blog

\n

简单来说,301 重定向是在告诉浏览器:“这个页面已经永久迁移了。这个是新的地址,我们不打算把它移回去啦。”这时,浏览器会回复:“没问题!我现在(开始)就把用户引向这里!”

\n

这就是为什么访问 blog.ahrefs.com 已经不可能了。你最后会去到的网页是 ahrefs.com/blog。

\n

前提条件

\n

前提条件可以分为有服务器无服务器两种情况,下面具体说一下。

\n
    \n
  1. \n

    有服务器(可以考虑腾讯云或者阿里云的轻量云服务器,双十一优惠价一年也就几十块);

    \n
      \n
    • 阿里云轻量云服务器:购买链接
    • \n
    • 腾讯云轻量云服务器:购买链接
    • \n
    • 域名(域名需要已经完成备案);
    • \n
    • SSL 证书(可以使用阿里云或者腾讯云的免费域名证书);
    • \n
    \n
  2. \n
  3. \n

    无服务器

    \n
      \n
    • 可以考虑使用 Cloudflare Page Rules(页面规则);当然,其他的平台也可以;
    • \n
    • 域名(有些域名可以不用备案);
    • \n
    • SSL 证书(如果你用的是 Cloudflare Page Rules,可以不用 SSL 证书 )。
    • \n
    \n
  4. \n
\n

操作步骤:有服务器

\n

本操作以 ncbix.com 域名为示例。

\n

1. 域名解析

\n

在你的域名供应商后台点击“添加记录”,分别输入 www 和 @,记录类型“A”,记录值就是你虚拟主机或 VPS 服务器的 IP 地址,最后保存。以 DNSPOD 为例。
\nimage.png

\n

2. SSL 证书

\n

申请免费证书,具体操作可以自行百度。以腾讯云为例:https://console.cloud.tencent.com/ssl
\nimage.png
\n根据截图,一步步点击操作。申请完成后,把证书下载并上传到你的服务器。
\nimage.png

\n

3. 安装 Nginx

\n

可以直接使用 yum/apt 的方式直接安装;源码方式的安装,参考:《CentOS 7 下编译安装 Nginx · 语雀》。

\n
# Debian/Ubuntu\napt update\napt install nginx\n\n# CentOS/RHEL\nyum install nginx
\n

4. 配置 Nginx

\n

通过 yum/apt 安装的 Nginx 默认的置文件在 /etc/nginx/nginx.conf,编辑该文件。

\n
http {\n    ##\n    # Basic Settings\n    ##\n    ......\n\n    ##\n    # Virtual Host Configs\n    ##\nserver {\n    listen 80;\n    listen 443 ssl;\n    server_name ncbix.com www.ncbix.com;\n    ssl_certificate /etc/nginx/ssl/nginx/www.ncbix.com_bundle.crt;\n    ssl_certificate_key /etc/nginx/ssl/nginx/www.ncbix.com.key;\n    index  index.php index.html index.htm;\n\n    if ( $scheme = "http" ) {\n        return 301 https://www.yuque.com/shenweiyan$request_uri; #确保跳转到新域名HTTPS如果没有HTTPS可以去掉\n    }\n    location / {\n        rewrite /.* https://www.yuque.com/shenweiyan$uri redirect; #跳转到新域名并重写为新域名\n    }\n  }\n\ninclude /etc/nginx/conf.d/*.conf;\n    include /etc/nginx/sites-enabled/*;\n}
\n

5. 重启 Nginx

\n

最后,通过下面的命令重启 Nginx 服务即可。

\n
service nginx restart
\n

操作步骤:无服务器

\n

我们以 Cloudflare Page Rules 为例,说明一下具体怎么操作。

\n

1. Cloudflare 中添加站点

\n

image.png

\n

添加完站点后,可以选择 Free 计划,然后点击继续:
\nimage.png

\n

点击继续后,Cloudflare 会自动扫描你对应域名的一些解析记录:
\nimage.png

\n

我们可以直接选择 "继续"
\nimage.png

\n

2. 修改域名 DNS

\n

首先,我的域名是在腾讯云注册的,可以去腾讯云控制台 "我的域名" 中直接修改 DNS:

\n
# 添加 Cloudflare 名称服务器\nimani.ns.cloudflare.com\ncaroline.dnspod.net\n
\n

image.png
\nimage.png

\n

3. 完成 Cloudflare 添加站点

\n

可以把后面快速指南的这几个配置都勾选。
\nimage.png

\n

等待几分钟就可以看到你的域名站点已经添加到 Cloudflare 上了!
\nimage.png

\n

4. 设置 DNS 记录

\n
\n

The first thing you will need is a DNS record for @, www and any other subdomains you want to redirect, set to image.png. This can point to any IP address as the redirection page rule will execute first. I would recommend pointing them to 192.0.2.1 , a dummy IP.

\n

From:https://community.cloudflare.com/t/redirecting-one-domain-to-another/81960

\n
\n

在配置 Cloudflare 站点的页面规则前,你需要把该域名的 @www 或者其他你想要进行重定向的子域名添加到 DNS 记录中,这个记录的值可以指向任何 IP 地址,因为重定向页面规则将首先执行。我建议将它们指向 192.0.2.1 ,一个虚拟 IP。

\n

在这里,我们以 @note 子域名为例,添加 DNS 记录,先让它们指向一个虚拟 IP。
\nimages

\n

5. 配置 Cloudflare 站点页面规则

\n

首先,在 Cloudflare 的主页上点击对应的站点,选择 "页面规则",点击。
\nimage.png

\n

点击 "创建页面规则"
\nimage.png
\nimage.png
\nimage.png
\nimage.png

\n

什么是页面规则?

\n
\n

页面规则为 Cloudflare 设置提供基于 URL 的粒度控制。关于页面规则需要了解的最重要事情是,针对一个 URL 仅触发一个页面规则,因此一定要按照优先级顺序对页面规则进行排序并将最具体的页面规则放在顶部。

\n
\n
页面规则中允许哪些模式?
\n
\n

如果使用的是转发页面规则,则可以将这些通配符映射到变量。在转发 URL 中,可以按照从左到右的顺序指定与原始 URL 中的通配符相匹配的 $1、$2,以此类推。

\n

例如,可以将 http://.example.com/ 转发到 http://$2.example.com/$1.jpg。此规则将与 http://cloud.example.com/flare 相匹配,这最终将转发到 http://flare.example.com/cloud.jpg

\n
\n
一些有用的提示:
\n
\n
    \n
  1. 如果要同时匹配 http 和 https,只需编写 example.com 即可。无需编写 example.com。
  2. \n
  3. 如果要匹配域中的每个页面,则需要编写 example.com/,仅编写 example.com 是不够的。
  4. \n
  5. 请参阅 了解和配置 Cloudflare 页面规则 了解有关页面规则模式的更多详细信息。
  6. \n
\n
\n

6. 配置 SSL(不必要)

\n

📢 Update 2022.09.05:这一步不是必要的,这里仅供参考!

\n
    \n
  1. 申请 www.example.com 域名的 SSL 证书;
  2. \n
  3. 把 DNS 验证域名的记录添加到 Cloudfare 的 DNS 中;
  4. \n
\n

image.png
\nimage.png
\nimage.png

\n

注意:
\nimage.png

\n

参考资料

\n
    \n
  1. nginx 实现两个域名之间跳转配置 - SegmentFault 思否
  2. \n
  3. 智能云解析 DNS - 通过 Nginx 实现 URL 转发 | 百度智能云文档
  4. \n
  5. SEO 的 301 重定向:你需要知道的一切
  6. \n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '1.3-折腾'}, 'labels': {'nodes': [{'name': '语雀'}]}, 'comments': {'nodes': []}}, {'title': 'Python 导出公众号文章为 Markdown', 'number': 7, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/7', 'createdAt': '2023-10-19T03:21:58Z', 'lastEditedAt': '2023-10-19T03:32:09Z', 'updatedAt': '2023-10-19T03:32:09Z', 'body': '记录一下个人使用 Python3 爬取个人公众号的所有文章,并把文章保存为 Markdown 格式的一些操作记录,主要介绍一下思路和一些简单的代码。\r\n\r\n\r\n\r\n## 前提条件与思路\r\n\r\n1. 需要登录网页端微信公众号,获取对应 Cookies;\r\n2. 通过获取的 Cookies 爬取所有的文章 url 以及其他信息;\r\n3. 通过文章 url 获取对应文章的 HTML;\r\n4. 最后,把 HTML 转化为 Markdown。\r\n\r\n之所以选择通过文章公开访问的 url 爬取对应文章的 HTML,而不是直接沿用 Cookies,主要是怕 Cookies 滥用导致其他不可预知的问题,例如封号之类。截止本文章发布前,个人公众号全部已发表的文章大约有 400 多篇,通过这个方法都能正常爬取下来。\r\n\r\n## 获取已发表文章数\r\n\r\n登录公众号,按下 F12 打开开发者工具,在 `网络` 栏中找到 `appmsgpublish` 名称的请求。\r\n\r\n- 查看请求地址\r\n ![appmsgpublish url](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/Gitbook/wechat_url.png)\r\n\r\n- 获取 cookie\r\n ![wecaht cookie](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/Gitbook/wecaht_cookie.png)\r\n\r\n```python\r\nimport requests, json\r\n\r\n#注意把 替换成你自己的 cookie\r\nheaders = {\'Content-type\': \'application/json\', \'User-Agent\': \'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36\',\r\n \'Cookie\': }\r\n\r\n#这个 url 即截图中的请求地址\r\nurl = \'https://mp.weixin.qq.com/cgi-bin/appmsgpublish?sub=list&search_field=null&begin=0&count=5&query=&type=101_1&free_publish_type=1&sub_action=list_ex&token=&lang=zh_CN&f=json&ajax=1\'\r\nreq = requests.get(url, headers=headers)\r\nreq_json = json.loads(req.content.decode("utf-8"))\r\nreq_json\r\n# total_count 即为已发表文章的总数\r\n```\r\n![Wecaht posts total_count](https://slab-1251708715.cos.ap-guangzhou.myqcloud.com/Gitbook/total_count.png)\r\n\r\n## 获取所有的文章信息\r\n\r\n以下程序的 `mp.txt` 就是得到的该公众号所有文章信息的列表。\r\n\r\n```python\r\nallPostList = []\r\n\r\nfor number in range(0, 420, 20):\r\n #注意 begin={number}&count=20,即按照每页20篇文章,分页进行爬取\r\n #根据测试每页最多只支持20篇文章\r\n url = f"https://mp.weixin.qq.com/cgi-bin/appmsgpublish?sub=list&search_field=null&begin={number}&count=20&query=&type=101_1&free_publish_type=1&sub_action=list_ex&token=&lang=zh_CN&f=json&ajax=1\', headers=headers)"\r\n x = requests.get(url, headers=headers)\r\n posts_list = json.loads(json.loads(x.content.decode("utf-8"))[\'publish_page\'])["publish_list"]\r\n allPostList = allPostList + posts_list \r\n time.sleep(5)\r\n\r\nwith open("mp.txt", "w") as OUT:\r\n OUT.write(str(allPostList))\r\n```\r\n\r\n## HTML to Markdown\r\n\r\nPython 导出公众号文章为 Markdown 最后的一步工作就是解析上一步骤得到的 `mp.txt` 文件,然后通过 url 去逐一爬取对应的文章 HTML,然后把 Html 转化成 Markdown 即可。\r\n\r\n这些步骤都很简单,网上搜一下就有一大堆教程,感兴趣的可以去搜一下,这里文章就不写了。 \r\n\r\n', 'bodyText': '记录一下个人使用 Python3 爬取个人公众号的所有文章,并把文章保存为 Markdown 格式的一些操作记录,主要介绍一下思路和一些简单的代码。\n\n前提条件与思路\n\n需要登录网页端微信公众号,获取对应 Cookies;\n通过获取的 Cookies 爬取所有的文章 url 以及其他信息;\n通过文章 url 获取对应文章的 HTML;\n最后,把 HTML 转化为 Markdown。\n\n之所以选择通过文章公开访问的 url 爬取对应文章的 HTML,而不是直接沿用 Cookies,主要是怕 Cookies 滥用导致其他不可预知的问题,例如封号之类。截止本文章发布前,个人公众号全部已发表的文章大约有 400 多篇,通过这个方法都能正常爬取下来。\n获取已发表文章数\n登录公众号,按下 F12 打开开发者工具,在 网络 栏中找到 appmsgpublish 名称的请求。\n\n\n查看请求地址\n\n\n\n获取 cookie\n\n\n\nimport requests, json\n\n#注意把 替换成你自己的 cookie\nheaders = {\'Content-type\': \'application/json\', \'User-Agent\': \'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36\',\n \'Cookie\': }\n\n#这个 url 即截图中的请求地址\nurl = \'https://mp.weixin.qq.com/cgi-bin/appmsgpublish?sub=list&search_field=null&begin=0&count=5&query=&type=101_1&free_publish_type=1&sub_action=list_ex&token=&lang=zh_CN&f=json&ajax=1\'\nreq = requests.get(url, headers=headers)\nreq_json = json.loads(req.content.decode("utf-8"))\nreq_json\n# total_count 即为已发表文章的总数\n\n获取所有的文章信息\n以下程序的 mp.txt 就是得到的该公众号所有文章信息的列表。\nallPostList = []\n\nfor number in range(0, 420, 20):\n #注意 begin={number}&count=20,即按照每页20篇文章,分页进行爬取\n #根据测试每页最多只支持20篇文章\n url = f"https://mp.weixin.qq.com/cgi-bin/appmsgpublish?sub=list&search_field=null&begin={number}&count=20&query=&type=101_1&free_publish_type=1&sub_action=list_ex&token=&lang=zh_CN&f=json&ajax=1\', headers=headers)"\n x = requests.get(url, headers=headers)\n posts_list = json.loads(json.loads(x.content.decode("utf-8"))[\'publish_page\'])["publish_list"]\n allPostList = allPostList + posts_list \n time.sleep(5)\n\nwith open("mp.txt", "w") as OUT:\n OUT.write(str(allPostList))\nHTML to Markdown\nPython 导出公众号文章为 Markdown 最后的一步工作就是解析上一步骤得到的 mp.txt 文件,然后通过 url 去逐一爬取对应的文章 HTML,然后把 Html 转化成 Markdown 即可。\n这些步骤都很简单,网上搜一下就有一大堆教程,感兴趣的可以去搜一下,这里文章就不写了。', 'bodyHTML': '

记录一下个人使用 Python3 爬取个人公众号的所有文章,并把文章保存为 Markdown 格式的一些操作记录,主要介绍一下思路和一些简单的代码。

\n\n

前提条件与思路

\n
    \n
  1. 需要登录网页端微信公众号,获取对应 Cookies;
  2. \n
  3. 通过获取的 Cookies 爬取所有的文章 url 以及其他信息;
  4. \n
  5. 通过文章 url 获取对应文章的 HTML;
  6. \n
  7. 最后,把 HTML 转化为 Markdown。
  8. \n
\n

之所以选择通过文章公开访问的 url 爬取对应文章的 HTML,而不是直接沿用 Cookies,主要是怕 Cookies 滥用导致其他不可预知的问题,例如封号之类。截止本文章发布前,个人公众号全部已发表的文章大约有 400 多篇,通过这个方法都能正常爬取下来。

\n

获取已发表文章数

\n

登录公众号,按下 F12 打开开发者工具,在 网络 栏中找到 appmsgpublish 名称的请求。

\n
    \n
  • \n

    查看请求地址
    \nappmsgpublish url

    \n
  • \n
  • \n

    获取 cookie
    \nwecaht cookie

    \n
  • \n
\n
import requests, json\n\n#注意把 <Your Cookie> 替换成你自己的 cookie\nheaders = {\'Content-type\': \'application/json\', \'User-Agent\': \'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36\',\n           \'Cookie\': <Your Cookie>}\n\n#这个 url 即截图中的请求地址\nurl = \'https://mp.weixin.qq.com/cgi-bin/appmsgpublish?sub=list&search_field=null&begin=0&count=5&query=&type=101_1&free_publish_type=1&sub_action=list_ex&token=<token>&lang=zh_CN&f=json&ajax=1\'\nreq = requests.get(url, headers=headers)\nreq_json = json.loads(req.content.decode("utf-8"))\nreq_json\n# total_count 即为已发表文章的总数
\n

Wecaht posts total_count

\n

获取所有的文章信息

\n

以下程序的 mp.txt 就是得到的该公众号所有文章信息的列表。

\n
allPostList = []\n\nfor number in range(0, 420, 20):\n    #注意 begin={number}&count=20,即按照每页20篇文章,分页进行爬取\n    #根据测试每页最多只支持20篇文章\n    url = f"https://mp.weixin.qq.com/cgi-bin/appmsgpublish?sub=list&search_field=null&begin={number}&count=20&query=&type=101_1&free_publish_type=1&sub_action=list_ex&token=<token>&lang=zh_CN&f=json&ajax=1\', headers=headers)"\n    x = requests.get(url, headers=headers)\n    posts_list  = json.loads(json.loads(x.content.decode("utf-8"))[\'publish_page\'])["publish_list"]\n    allPostList = allPostList + posts_list  \n    time.sleep(5)\n\nwith open("mp.txt", "w") as OUT:\n    OUT.write(str(allPostList))
\n

HTML to Markdown

\n

Python 导出公众号文章为 Markdown 最后的一步工作就是解析上一步骤得到的 mp.txt 文件,然后通过 url 去逐一爬取对应的文章 HTML,然后把 Html 转化成 Markdown 即可。

\n

这些步骤都很简单,网上搜一下就有一大堆教程,感兴趣的可以去搜一下,这里文章就不写了。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '2023年下半年的一些乱弹', 'number': 6, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/6', 'createdAt': '2023-10-18T02:46:03Z', 'lastEditedAt': '2023-11-29T01:09:10Z', 'updatedAt': '2023-11-29T01:09:10Z', 'body': '其实写这边文章,主要是想着测试一下使用了 GitHub Actions 的 mkdocs 触发 Discussions to mkdocs blog posts 的一些效果。\r\n\r\n\r\n\r\n今天的天气真好啊!阳光明媚,微风拂面,仿佛是一幅美丽的画卷。这样的天气让人心情愉悦,忍不住想要出去走走,感受大自然的美丽。无论是散步还是骑自行车,都是不错的选择。我享受着这美好的一天,也期待着未来更多美好的时光。\r\n\r\n从 11 月起,公司也好,家庭也罢,陆陆续续的一些事情让生活变得此起彼伏。缺乏了一些码字的动力,整个人变得有点沮丧,空洞夹杂着混沌的状态让整个人都很显得颓废。生活需要激情,希望接下来的 12 月能回归一个更好的状态吧!', 'bodyText': '其实写这边文章,主要是想着测试一下使用了 GitHub Actions 的 mkdocs 触发 Discussions to mkdocs blog posts 的一些效果。\n\n今天的天气真好啊!阳光明媚,微风拂面,仿佛是一幅美丽的画卷。这样的天气让人心情愉悦,忍不住想要出去走走,感受大自然的美丽。无论是散步还是骑自行车,都是不错的选择。我享受着这美好的一天,也期待着未来更多美好的时光。\n从 11 月起,公司也好,家庭也罢,陆陆续续的一些事情让生活变得此起彼伏。缺乏了一些码字的动力,整个人变得有点沮丧,空洞夹杂着混沌的状态让整个人都很显得颓废。生活需要激情,希望接下来的 12 月能回归一个更好的状态吧!', 'bodyHTML': '

其实写这边文章,主要是想着测试一下使用了 GitHub Actions 的 mkdocs 触发 Discussions to mkdocs blog posts 的一些效果。

\n\n

今天的天气真好啊!阳光明媚,微风拂面,仿佛是一幅美丽的画卷。这样的天气让人心情愉悦,忍不住想要出去走走,感受大自然的美丽。无论是散步还是骑自行车,都是不错的选择。我享受着这美好的一天,也期待着未来更多美好的时光。

\n

从 11 月起,公司也好,家庭也罢,陆陆续续的一些事情让生活变得此起彼伏。缺乏了一些码字的动力,整个人变得有点沮丧,空洞夹杂着混沌的状态让整个人都很显得颓废。生活需要激情,希望接下来的 12 月能回归一个更好的状态吧!

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '2.1-乱弹'}, 'labels': {'nodes': []}, 'comments': {'nodes': [{'body': 'Hello,Wed Oct 18 10:46:41 CST 2023', 'author': {'login': 'shenweiyan'}}]}}, {'title': '友情链接', 'number': 5, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/5', 'createdAt': '2023-10-16T07:57:49Z', 'lastEditedAt': '2024-11-05T07:13:09Z', 'updatedAt': '2024-11-05T07:13:09Z', 'body': '> 每一个独立博客都是一个信息孤岛。我们没有类似「你可能喜欢其他人写的这些文章」的推荐机制,所以除了搜索引擎、社交网络引荐之外,我们应该还需要通过某种方法将这些信息孤岛连接起来:**交换友情链接就是一种很棒的架桥方式。**\r\n\r\n社交就是不断认识新的人、结交新的朋友,而友链也正是这样一种很棒的交朋友的方式,作为一个不太善于言辞的技术人,我希望结交更多的朋友,来丰富我的社交,一起成长。\r\n\r\n## 站点信息\r\n\r\n交换友链前可先添加个人站点,站点信息如下。\r\n\r\n- 站点名称: 维燕的知识花园\r\n- 站点链接: \r\n- 站点头像: \r\n- 站点描述: Bio & IT 爱好者,沉淀生活,记录点滴。\r\n\r\n## 交换友链\r\n\r\n想和我交换友链的,没啥特别需求,只是希望你的博客有足够多的**原创**、**有意义**的内容,并且建站已满半年。\r\n\r\n- 那种塞满了转载文章的采集站点暂时不考虑。\r\n- 非常反感很多论坛上动不动就来交换友链的帖子,如果是出于 SEO 的一些目的来交换友链其实是没什么意义的。\r\n\r\n## 友链说明\r\n\r\n如需申请,在下方评论区提供你的「博客名称」和「博客地址」即可。或者参考以下格式:\r\n\r\n- 博客名称:xxxxx\r\n- 博客地址:https://xxxx.com\r\n- 博客介绍:xxxxxxxx\r\n\r\n## 友情站点\r\n\r\n以下站点按照添加的时间顺序排列。\r\n\r\n
\r\n\r\n- __[UncleCAT4](https://yuanj.top/)__\r\n\r\n 思绪来得快去得也快,偶尔会在这里停留。\r\n\r\n- __[1874’s Blog](https://blog.1874.cool)__\r\n\r\n 有粤语歌就不会有世界末日。\r\n\r\n- __[望薮](https://ralvines.top)__\r\n\r\n 以我观物,故物皆著我之色彩。\r\n\r\n- __[Jayden\'s site](https://xxu.do/)__\r\n\r\n 为天地立心,为生民立命,为往圣继绝学,为万世开太平。\r\n\r\n- __[Shitao Wu | 吴诗涛](https://shitao5.org/)__\r\n\r\n 喜欢捣鼓电脑,UseR,喜欢[阅读](https://shitao5.org/tags/%E8%AF%BB%E5%90%8E%E6%84%9F/),重度使用 Kindle。甘愿做一个平庸的人,走在成为我自己的道路上。\r\n\r\n- __[椒盐豆豉](https://blog.douchi.space/)__\r\n\r\n 一个写了二十年博客,现居美国西雅图的女博主+码农。\r\n\r\n- __[墨迹心空](https://www.secondlife.love/)__\r\n\r\n Life is coding.\r\n\r\n- __[言成的个人博客](https://meethigher.top/)__\r\n\r\n 言成的个人博客网站,寓意为让我们相逢在更高处。\r\n\r\n- __[Pepper的博客](https://uioqps.github.io/)__\r\n\r\n 生命留给有价值的事物才能创造价值。\r\n\r\n- __[LINUX DO](https://linux.do/?source=weiyan_cc)__\r\n\r\n 新的理想型社区。\r\n\r\n
', 'bodyText': "每一个独立博客都是一个信息孤岛。我们没有类似「你可能喜欢其他人写的这些文章」的推荐机制,所以除了搜索引擎、社交网络引荐之外,我们应该还需要通过某种方法将这些信息孤岛连接起来:交换友情链接就是一种很棒的架桥方式。\n\n社交就是不断认识新的人、结交新的朋友,而友链也正是这样一种很棒的交朋友的方式,作为一个不太善于言辞的技术人,我希望结交更多的朋友,来丰富我的社交,一起成长。\n站点信息\n交换友链前可先添加个人站点,站点信息如下。\n\n站点名称: 维燕的知识花园\n站点链接: https://weiyan.cc\n站点头像: https://weiyan.cc/assets/logo.png\n站点描述: Bio & IT 爱好者,沉淀生活,记录点滴。\n\n交换友链\n想和我交换友链的,没啥特别需求,只是希望你的博客有足够多的原创、有意义的内容,并且建站已满半年。\n\n那种塞满了转载文章的采集站点暂时不考虑。\n非常反感很多论坛上动不动就来交换友链的帖子,如果是出于 SEO 的一些目的来交换友链其实是没什么意义的。\n\n友链说明\n如需申请,在下方评论区提供你的「博客名称」和「博客地址」即可。或者参考以下格式:\n\n博客名称:xxxxx\n博客地址:https://xxxx.com\n博客介绍:xxxxxxxx\n\n友情站点\n以下站点按照添加的时间顺序排列。\n\n\n\nUncleCAT4\n思绪来得快去得也快,偶尔会在这里停留。\n\n\n1874’s Blog\n有粤语歌就不会有世界末日。\n\n\n望薮\n以我观物,故物皆著我之色彩。\n\n\nJayden's site\n为天地立心,为生民立命,为往圣继绝学,为万世开太平。\n\n\nShitao Wu | 吴诗涛\n喜欢捣鼓电脑,UseR,喜欢阅读,重度使用 Kindle。甘愿做一个平庸的人,走在成为我自己的道路上。\n\n\n椒盐豆豉\n一个写了二十年博客,现居美国西雅图的女博主+码农。\n\n\n墨迹心空\nLife is coding.\n\n\n言成的个人博客\n言成的个人博客网站,寓意为让我们相逢在更高处。\n\n\nPepper的博客\n生命留给有价值的事物才能创造价值。\n\n\nLINUX DO\n新的理想型社区。", 'bodyHTML': '
\n

每一个独立博客都是一个信息孤岛。我们没有类似「你可能喜欢其他人写的这些文章」的推荐机制,所以除了搜索引擎、社交网络引荐之外,我们应该还需要通过某种方法将这些信息孤岛连接起来:交换友情链接就是一种很棒的架桥方式。

\n
\n

社交就是不断认识新的人、结交新的朋友,而友链也正是这样一种很棒的交朋友的方式,作为一个不太善于言辞的技术人,我希望结交更多的朋友,来丰富我的社交,一起成长。

\n

站点信息

\n

交换友链前可先添加个人站点,站点信息如下。

\n\n

交换友链

\n

想和我交换友链的,没啥特别需求,只是希望你的博客有足够多的原创有意义的内容,并且建站已满半年。

\n
    \n
  • 那种塞满了转载文章的采集站点暂时不考虑。
  • \n
  • 非常反感很多论坛上动不动就来交换友链的帖子,如果是出于 SEO 的一些目的来交换友链其实是没什么意义的。
  • \n
\n

友链说明

\n

如需申请,在下方评论区提供你的「博客名称」和「博客地址」即可。或者参考以下格式:

\n
    \n
  • 博客名称:xxxxx
  • \n
  • 博客地址:https://xxxx.com
  • \n
  • 博客介绍:xxxxxxxx
  • \n
\n

友情站点

\n

以下站点按照添加的时间顺序排列。

\n
\n
    \n
  • \n

    UncleCAT4

    \n

    思绪来得快去得也快,偶尔会在这里停留。

    \n
  • \n
  • \n

    1874’s Blog

    \n

    有粤语歌就不会有世界末日。

    \n
  • \n
  • \n

    望薮

    \n

    以我观物,故物皆著我之色彩。

    \n
  • \n
  • \n

    Jayden\'s site

    \n

    为天地立心,为生民立命,为往圣继绝学,为万世开太平。

    \n
  • \n
  • \n

    Shitao Wu | 吴诗涛

    \n

    喜欢捣鼓电脑,UseR,喜欢阅读,重度使用 Kindle。甘愿做一个平庸的人,走在成为我自己的道路上。

    \n
  • \n
  • \n

    椒盐豆豉

    \n

    一个写了二十年博客,现居美国西雅图的女博主+码农。

    \n
  • \n
  • \n

    墨迹心空

    \n

    Life is coding.

    \n
  • \n
  • \n

    言成的个人博客

    \n

    言成的个人博客网站,寓意为让我们相逢在更高处。

    \n
  • \n
  • \n

    Pepper的博客

    \n

    生命留给有价值的事物才能创造价值。

    \n
  • \n
  • \n

    LINUX DO

    \n

    新的理想型社区。

    \n
  • \n
\n
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '0.1-站点'}, 'labels': {'nodes': []}, 'comments': {'nodes': [{'body': '**我的站点信息** \r\n\r\n- 站点名称: 维燕的知识花园\r\n- 站点链接: https://weiyan.cc\r\n- 站点头像: https://weiyan.cc/assets/logo.png\r\n- 站点描述: Bio & IT 爱好者,沉淀生活,记录点滴。', 'author': {'login': 'shenweiyan'}}, {'body': '博客名称:Jayden\n博客地址:https://xxu.do\n博客介绍为天地立心,为生民立命, 为往圣继绝学,为万世开太平。\n', 'author': {'login': 'Jaaayden'}}, {'body': 'hello', 'author': {'login': 'vbskycn'}}, {'body': '站名:墨迹心空\n站点链接:https://www.secondlife.love\n站点介绍:life is coding', 'author': {'login': 'secondlife1127'}}, {'body': '你好,uioqps.github.io\n可以交流下技术相关的问题吗', 'author': {'login': 'uioQPS'}}]}}, {'title': '关于 | 作者与站点', 'number': 4, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/4', 'createdAt': '2023-10-16T05:11:48Z', 'lastEditedAt': '2024-08-16T01:32:02Z', 'updatedAt': '2024-08-16T01:32:02Z', 'body': '聊一聊关于作者和这个站点的一些事情。\r\n\r\n## 缘起\r\n\r\n程序员都有一个博客梦,对我来说,写写字也可以成为我调解压力的一个很好方式。\r\n\r\n在独立博客或者说独立站点前,一直有一种 "背靠大树好乘凉" 的心理把自己的文档建立的大平台的服务上,从开源中国、蚂蚁笔记、博客园、简书、CSDN、语雀上踩过不少坑后终于认识到数据可控和 DIY 的好处,于是有了独立博客站点的想法。\r\n\r\n静态博客站点一直是个人最情有独钟的选择,省去了服务器折腾续费运维的种种麻烦,可以更加专注于文字本身的写作。也曾经纠结过 Jekyll、Hexo、Hugo 的选型,但最终被 Hugo 极快的页面编译生成速度所折服,并深受[谢益辉](https://github.com/yihui)前期的 [ivy-hugo-theme](https://github.com/shenweiyan/ivy-hugo-theme) 博客风格影响,自己倒腾了一个 [ICS-Hugo-Theme](https://github.com/shenweiyan/ICS-Hugo-Theme) 用了好几年。\r\n\r\n## 语雀\r\n\r\n在独立博客站点前不得不把语雀单独拎出来说一下。\r\n\r\n从 2018 到 2023 年,语雀一直都是我重度使用的主力平台,没有之一。我也一度以为语雀会成为了未来 5-10 年的主力平台(由于[语雀天使](https://weiyan.cc/note/2021-10-14-yuque-vip/)的福利,我的语雀会员也延长到了 **2037** 年!),[All in Yuque](https://www.yuque.com/shenweiyan/notebook/all-in-yuque) 也成为了我那一段时间的坚持。不幸的是,语雀在 2023 年发生了非常严重的[宕机事件](https://www.zhihu.com/question/627448953),加上前一年沸沸扬扬的[收费事件](https://www.zhihu.com/question/562238887),以及语雀固有的一些问题,对于语雀的信任开始动摇。\r\n\r\n直至 2023 年由于工作地点的变更,加上某些不可描述的原因导致语雀在办公网络下无法直接访问,终于把继续使用语雀的最后一根稻草压垮,逐步开始拥抱 GitHub,并在这个全球最大的开源平台上深入摸索。\r\n\r\n## 当下\r\n\r\n正如个人在[语雀花园](https://www.yuque.com/shenweiyan)所说,2023年7月起个人大部分文章已经转移至 [GitHub](https://github.com/shenweiyan),并同步至 [Knowledge-Garden](https://github.com/shenweiyan/Knowledge-Garden/) (后期主要在 [Discussions](https://github.com/shenweiyan/Knowledge-Garden/discussions) 和 [知识花园](https://weiyan.cc/) 进行写作与更新),语雀会保持不定期更新(基本已经停更)!\r\n\r\n现在的这个站点是基于 [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/) 进行部署,并整合了个人 **[语雀知识库](https://www.yuque.com/shenweiyan)** 几个主要知识库文章后形成的独立站点。\r\n\r\n## 未来\r\n\r\n我希望 [WeiYan.CC](https://weiyan.cc/) 能成为我知识管理的最后一站,虽然未来这些文章展现的形式,或者选择用于部署的技术有所改变,但至少域名是不变的(除非我能有幸注册到 com/cn/net/org 其中之一的主流域名),通过这个域名你至少还能找到曾经我写下的那些字。\r\n\r\n不忘初心,方得始终,希望下一个十年,还能在这里遇到一个曾经的我,看到曾经的文字。\r\n\r\n## 作者\r\n\r\n沈维燕(史提芬先森/章鱼猫先生),一个 90 后的广东人,熟悉粤语、国语,略懂英语。\r\n\r\n- 毕业于南方医科大学(原中国人民解放军第一军医大学)基础医学院生物信息学专业。\r\n- 现工作生活于广州,主要从事 BIO & IT 的一些相关工作。\r\n- 平时喜欢逛逛技术论坛,玩玩羽毛球,看看电影,瞎折腾一下技术。\r\n- 不务正业之余喜欢记录一些生活工作学习中的一些想法。\r\n- 乐于分享,喜欢把事情简单化,程序化。\r\n\r\n## 联系\r\n\r\n个人目前用的比较多的沟通工具,一个是**邮箱**,另外一个是**微信**,你可以通过这两种方式直接和我联系。\r\n\r\n- 邮箱:(或者 )\r\n- 微信:ishenweiyan(添加微信好友,请注明真实姓名)\r\n\r\n!!! tip "请备注真名实姓,让我感受到一个真实的人的气息"\r\n 如果给我发**邮件**,或者通过**微信添加好友**,请写上您的**真名实姓**,让我感受到一个**真实的人**的气息。我不太愿意跟**网名**打交道,对于那些不知来路、上来就问问题的微信和邮件,我通常会直接忽略。', 'bodyText': '聊一聊关于作者和这个站点的一些事情。\n缘起\n程序员都有一个博客梦,对我来说,写写字也可以成为我调解压力的一个很好方式。\n在独立博客或者说独立站点前,一直有一种 "背靠大树好乘凉" 的心理把自己的文档建立的大平台的服务上,从开源中国、蚂蚁笔记、博客园、简书、CSDN、语雀上踩过不少坑后终于认识到数据可控和 DIY 的好处,于是有了独立博客站点的想法。\n静态博客站点一直是个人最情有独钟的选择,省去了服务器折腾续费运维的种种麻烦,可以更加专注于文字本身的写作。也曾经纠结过 Jekyll、Hexo、Hugo 的选型,但最终被 Hugo 极快的页面编译生成速度所折服,并深受谢益辉前期的 ivy-hugo-theme 博客风格影响,自己倒腾了一个 ICS-Hugo-Theme 用了好几年。\n语雀\n在独立博客站点前不得不把语雀单独拎出来说一下。\n从 2018 到 2023 年,语雀一直都是我重度使用的主力平台,没有之一。我也一度以为语雀会成为了未来 5-10 年的主力平台(由于语雀天使的福利,我的语雀会员也延长到了 2037 年!),All in Yuque 也成为了我那一段时间的坚持。不幸的是,语雀在 2023 年发生了非常严重的宕机事件,加上前一年沸沸扬扬的收费事件,以及语雀固有的一些问题,对于语雀的信任开始动摇。\n直至 2023 年由于工作地点的变更,加上某些不可描述的原因导致语雀在办公网络下无法直接访问,终于把继续使用语雀的最后一根稻草压垮,逐步开始拥抱 GitHub,并在这个全球最大的开源平台上深入摸索。\n当下\n正如个人在语雀花园所说,2023年7月起个人大部分文章已经转移至 GitHub,并同步至 Knowledge-Garden (后期主要在 Discussions 和 知识花园 进行写作与更新),语雀会保持不定期更新(基本已经停更)!\n现在的这个站点是基于 Material for MkDocs 进行部署,并整合了个人 语雀知识库 几个主要知识库文章后形成的独立站点。\n未来\n我希望 WeiYan.CC 能成为我知识管理的最后一站,虽然未来这些文章展现的形式,或者选择用于部署的技术有所改变,但至少域名是不变的(除非我能有幸注册到 com/cn/net/org 其中之一的主流域名),通过这个域名你至少还能找到曾经我写下的那些字。\n不忘初心,方得始终,希望下一个十年,还能在这里遇到一个曾经的我,看到曾经的文字。\n作者\n沈维燕(史提芬先森/章鱼猫先生),一个 90 后的广东人,熟悉粤语、国语,略懂英语。\n\n毕业于南方医科大学(原中国人民解放军第一军医大学)基础医学院生物信息学专业。\n现工作生活于广州,主要从事 BIO & IT 的一些相关工作。\n平时喜欢逛逛技术论坛,玩玩羽毛球,看看电影,瞎折腾一下技术。\n不务正业之余喜欢记录一些生活工作学习中的一些想法。\n乐于分享,喜欢把事情简单化,程序化。\n\n联系\n个人目前用的比较多的沟通工具,一个是邮箱,另外一个是微信,你可以通过这两种方式直接和我联系。\n\n邮箱:shen@weiyan.cc(或者 shen@weiyan.tech)\n微信:ishenweiyan(添加微信好友,请注明真实姓名)\n\n!!! tip "请备注真名实姓,让我感受到一个真实的人的气息"\n如果给我发邮件,或者通过微信添加好友,请写上您的真名实姓,让我感受到一个真实的人的气息。我不太愿意跟网名打交道,对于那些不知来路、上来就问问题的微信和邮件,我通常会直接忽略。', 'bodyHTML': '

聊一聊关于作者和这个站点的一些事情。

\n

缘起

\n

程序员都有一个博客梦,对我来说,写写字也可以成为我调解压力的一个很好方式。

\n

在独立博客或者说独立站点前,一直有一种 "背靠大树好乘凉" 的心理把自己的文档建立的大平台的服务上,从开源中国、蚂蚁笔记、博客园、简书、CSDN、语雀上踩过不少坑后终于认识到数据可控和 DIY 的好处,于是有了独立博客站点的想法。

\n

静态博客站点一直是个人最情有独钟的选择,省去了服务器折腾续费运维的种种麻烦,可以更加专注于文字本身的写作。也曾经纠结过 Jekyll、Hexo、Hugo 的选型,但最终被 Hugo 极快的页面编译生成速度所折服,并深受谢益辉前期的 ivy-hugo-theme 博客风格影响,自己倒腾了一个 ICS-Hugo-Theme 用了好几年。

\n

语雀

\n

在独立博客站点前不得不把语雀单独拎出来说一下。

\n

从 2018 到 2023 年,语雀一直都是我重度使用的主力平台,没有之一。我也一度以为语雀会成为了未来 5-10 年的主力平台(由于语雀天使的福利,我的语雀会员也延长到了 2037 年!),All in Yuque 也成为了我那一段时间的坚持。不幸的是,语雀在 2023 年发生了非常严重的宕机事件,加上前一年沸沸扬扬的收费事件,以及语雀固有的一些问题,对于语雀的信任开始动摇。

\n

直至 2023 年由于工作地点的变更,加上某些不可描述的原因导致语雀在办公网络下无法直接访问,终于把继续使用语雀的最后一根稻草压垮,逐步开始拥抱 GitHub,并在这个全球最大的开源平台上深入摸索。

\n

当下

\n

正如个人在语雀花园所说,2023年7月起个人大部分文章已经转移至 GitHub,并同步至 Knowledge-Garden (后期主要在 Discussions知识花园 进行写作与更新),语雀会保持不定期更新(基本已经停更)!

\n

现在的这个站点是基于 Material for MkDocs 进行部署,并整合了个人 语雀知识库 几个主要知识库文章后形成的独立站点。

\n

未来

\n

我希望 WeiYan.CC 能成为我知识管理的最后一站,虽然未来这些文章展现的形式,或者选择用于部署的技术有所改变,但至少域名是不变的(除非我能有幸注册到 com/cn/net/org 其中之一的主流域名),通过这个域名你至少还能找到曾经我写下的那些字。

\n

不忘初心,方得始终,希望下一个十年,还能在这里遇到一个曾经的我,看到曾经的文字。

\n

作者

\n

沈维燕(史提芬先森/章鱼猫先生),一个 90 后的广东人,熟悉粤语、国语,略懂英语。

\n
    \n
  • 毕业于南方医科大学(原中国人民解放军第一军医大学)基础医学院生物信息学专业。
  • \n
  • 现工作生活于广州,主要从事 BIO & IT 的一些相关工作。
  • \n
  • 平时喜欢逛逛技术论坛,玩玩羽毛球,看看电影,瞎折腾一下技术。
  • \n
  • 不务正业之余喜欢记录一些生活工作学习中的一些想法。
  • \n
  • 乐于分享,喜欢把事情简单化,程序化。
  • \n
\n

联系

\n

个人目前用的比较多的沟通工具,一个是邮箱,另外一个是微信,你可以通过这两种方式直接和我联系。

\n\n

!!! tip "请备注真名实姓,让我感受到一个真实的人的气息"
\n如果给我发邮件,或者通过微信添加好友,请写上您的真名实姓,让我感受到一个真实的人的气息。我不太愿意跟网名打交道,对于那些不知来路、上来就问问题的微信和邮件,我通常会直接忽略。

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '0.1-站点'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': 'Discussions 3', 'number': 3, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/3', 'createdAt': '2023-10-16T05:03:33Z', 'lastEditedAt': '2023-11-08T08:03:02Z', 'updatedAt': '2023-12-06T01:35:06Z', 'body': 'Wed Nov 8 14:39:48 CST 2023', 'bodyText': 'Wed Nov 8 14:39:48 CST 2023', 'bodyHTML': '

Wed Nov 8 14:39:48 CST 2023

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '公告说明'}, 'labels': {'nodes': []}, 'comments': {'nodes': [{'body': '这里测试一下回复~', 'author': {'login': 'shenweiyan'}}, {'body': '在 Mkdocs 中插入指定的 discussions 以嵌入评论,其中 `data-term` 为对应的 discussions number~\r\n```\r\n\r\n```', 'author': {'login': 'shenweiyan'}}]}}, {'title': '这是一个备用讨论', 'number': 2, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/2', 'createdAt': '2023-10-16T05:03:14Z', 'lastEditedAt': '2023-12-05T06:33:23Z', 'updatedAt': '2023-12-05T06:33:23Z', 'body': '备用讨论', 'bodyText': '备用讨论', 'bodyHTML': '

备用讨论

', 'author': {'login': 'shenweiyan'}, 'category': {'name': '公告说明'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}, {'title': '使用与说明', 'number': 1, 'url': 'https://github.com/shenweiyan/Knowledge-Garden/discussions/1', 'createdAt': '2023-10-16T03:18:39Z', 'lastEditedAt': '2024-05-08T02:39:50Z', 'updatedAt': '2024-05-08T02:39:50Z', 'body': '分享一下我的经验。你也可以用 Github Discussions 搭建自己的论坛、博客、个人笔记等。\r\n\r\n## 欢迎订阅\r\n\r\n用户有自主选择权,只看他感兴趣的内容。\r\n\r\n1. 可以点击项目的 Watch 按钮来订阅消息。具体用法请看 [Github - 查看订阅](https://docs.github.com/zh/account-and-profile/managing-subscriptions-and-notifications-on-github/managing-subscriptions-for-activity-on-github/viewing-your-subscriptions)。\r\n watch-discussions\r\n\r\n 2. 也可以只订阅某个讨论。进入某个讨论,点击右边 Notifications 的 Subscribe 按钮。\r\n \r\n 用户可以在 https://github.com/notifications 里看到订阅的新消息。\r\n\r\n\r\n## 👋 Welcome!\r\n We’re using Discussions as a place to connect with other members of our community. We hope that you:\r\n * Ask questions you’re wondering about.\r\n * Share ideas.\r\n * Engage with other community members.\r\n * Welcome others and are open-minded. Remember that this is a community we\r\n build together 💪.\r\n\r\n To get started, comment below with an introduction of yourself and tell us about what you do with this community.\r\n\r\n\r\n\r\n## 本仓库谈论说明\r\n\r\n这里所有的 `Discussion Format` 都是 `Announcement`:Only maintainers and admins can post new discussions in these categories, but anyone can comment and reply. \r\n![Discussion Format](https://kg.weiyan.cc/2023/12/discussion-format.png)\r\n\r\n## 使用讨论 (Discussion)\r\n\r\n### 搜索讨论\r\n\r\n- 版块搜索:在 Discussions 页面的搜索框输入搜索词即可。\r\n- 全局搜索:在最上面的 Github 搜索框输入 `org:shenweiyan 搜索词` 就能搜索所有版块的讨论。比如搜["生信"](https://github.com/search?q=org%3Ashenweiyan+%E7%94%9F%E4%BF%A1&type=discussions)。\r\n \r\n### 排序讨论\r\n\r\n- 可以按时间来排序讨论。 \r\n sort-discussions\r\n \r\n### 使用 Label 筛选讨论\r\n- Label 是可以无限加的。一个讨论可以有多个 Label。 \r\n filter-labels\r\n\r\n- 标记 Label 的好处在于,用户可以在讨论列表里筛选、多选、反选 Label 对应的讨论。 \r\n filter-by-labels\r\n \r\n## 评论\r\n\r\n评论有两种。一种是在别人的评论下继续回复评论。一种是最底下的评论框,这会回复到主线里。\r\n \r\n如果你针对某个评论进行回复,建议在别人的评论下回复,不要回复到主线。这样其他订阅这个讨论的人不会收到消息提醒的干扰。\r\n \r\n## 讨论管理\r\n\r\n### 讨论分类\r\n\r\n讨论分类由项目管理员维护。按需创建。分类根据名称排序。所以加个数字前缀用来控制显示顺序。\r\n\r\n### 删除讨论\r\n\r\n点进讨论详情页,在右侧最底下有个 delete discussion。\r\n\r\n### 迁移讨论\r\n\r\n- Transfer this discussion 功能可以把讨论移到同组织的另一个项目下。 \r\n transfer-discussion\r\n\r\n- 也可以切换讨论分类。 \r\n change-category\r\n\r\n### 置顶讨论\r\n\r\n在讨论详情页面可以选择置到项目 Discussion 的顶部,或者置到讨论分类的顶部。\r\n置顶讨论\r\n\r\n## 周报月报\r\n可以考虑使用 Github Action 自动跑脚本,通过 Github API 来获取 Discussion 的消息。然后自动创建 release,把简报内容写到 release body 里。这样订阅了项目 release 的人就可以收到。 可以单独创建一个项目来管理,避免订阅的人受到干扰。\r\n\r\nGithub Discussion API:\r\n\r\n* https://docs.github.com/en/search-github/searching-on-github/searching-discussions\r\n* https://docs.github.com/en/graphql/guides/using-the-graphql-api-for-discussions#search\r\n* [Discussions API\xa0community/community#43](https://github.com/orgs/community/discussions/43)\r\n\r\n## 数据备份\r\n\r\n可以考虑使用 Github Action 自动跑脚本,通过 Github API 来获取 Discussion 的消息。\r\n \r\n\r\n## 移动端\r\nGithub 有[移动端 App](https://github.com/mobile)。除了不支持 Polls 功能,其他功能都挺好用的。能查看提醒,也能发布新讨论,也能回复评论。\r\n\r\n## 邮件端\r\n消息提醒同时会发到你绑定的邮箱里。你也可以用邮箱来查收。\r\n\r\n## 博文中加评论\r\n\r\n借助 [giscus](https://giscus.app/zh-CN),可以非常方便在文章页中插入指定的 discussions —— 在导出 discussions 的时候,在文章尾部增加类似以下 JavaScript 即可:\r\n```javascript\r\n\r\n```\r\n', 'bodyText': '分享一下我的经验。你也可以用 Github Discussions 搭建自己的论坛、博客、个人笔记等。\n欢迎订阅\n用户有自主选择权,只看他感兴趣的内容。\n\n\n可以点击项目的 Watch 按钮来订阅消息。具体用法请看 Github - 查看订阅。\n\n\n\n也可以只订阅某个讨论。进入某个讨论,点击右边 Notifications 的 Subscribe 按钮。\n用户可以在 https://github.com/notifications 里看到订阅的新消息。\n\n\n\n👋 Welcome!\nWe’re using Discussions as a place to connect with other members of our community. We hope that you:\n\nAsk questions you’re wondering about.\nShare ideas.\nEngage with other community members.\nWelcome others and are open-minded. Remember that this is a community we\nbuild together 💪.\n\nTo get started, comment below with an introduction of yourself and tell us about what you do with this community.\n\n本仓库谈论说明\n这里所有的 Discussion Format 都是 Announcement:Only maintainers and admins can post new discussions in these categories, but anyone can comment and reply.\n\n使用讨论 (Discussion)\n搜索讨论\n\n版块搜索:在 Discussions 页面的搜索框输入搜索词即可。\n全局搜索:在最上面的 Github 搜索框输入 org:shenweiyan 搜索词 就能搜索所有版块的讨论。比如搜"生信"。\n\n排序讨论\n\n可以按时间来排序讨论。\n\n\n使用 Label 筛选讨论\n\n\nLabel 是可以无限加的。一个讨论可以有多个 Label。\n\n\n\n标记 Label 的好处在于,用户可以在讨论列表里筛选、多选、反选 Label 对应的讨论。\n\n\n\n评论\n评论有两种。一种是在别人的评论下继续回复评论。一种是最底下的评论框,这会回复到主线里。\n如果你针对某个评论进行回复,建议在别人的评论下回复,不要回复到主线。这样其他订阅这个讨论的人不会收到消息提醒的干扰。\n讨论管理\n讨论分类\n讨论分类由项目管理员维护。按需创建。分类根据名称排序。所以加个数字前缀用来控制显示顺序。\n删除讨论\n点进讨论详情页,在右侧最底下有个 delete discussion。\n迁移讨论\n\n\nTransfer this discussion 功能可以把讨论移到同组织的另一个项目下。\n\n\n\n也可以切换讨论分类。\n\n\n\n置顶讨论\n在讨论详情页面可以选择置到项目 Discussion 的顶部,或者置到讨论分类的顶部。\n\n周报月报\n可以考虑使用 Github Action 自动跑脚本,通过 Github API 来获取 Discussion 的消息。然后自动创建 release,把简报内容写到 release body 里。这样订阅了项目 release 的人就可以收到。 可以单独创建一个项目来管理,避免订阅的人受到干扰。\nGithub Discussion API:\n\nhttps://docs.github.com/en/search-github/searching-on-github/searching-discussions\nhttps://docs.github.com/en/graphql/guides/using-the-graphql-api-for-discussions#search\nDiscussions API\xa0community/community#43\n\n数据备份\n可以考虑使用 Github Action 自动跑脚本,通过 Github API 来获取 Discussion 的消息。\n移动端\nGithub 有移动端 App。除了不支持 Polls 功能,其他功能都挺好用的。能查看提醒,也能发布新讨论,也能回复评论。\n邮件端\n消息提醒同时会发到你绑定的邮箱里。你也可以用邮箱来查收。\n博文中加评论\n借助 giscus,可以非常方便在文章页中插入指定的 discussions —— 在导出 discussions 的时候,在文章尾部增加类似以下 JavaScript 即可:\n', 'bodyHTML': '

分享一下我的经验。你也可以用 Github Discussions 搭建自己的论坛、博客、个人笔记等。

\n

欢迎订阅

\n

用户有自主选择权,只看他感兴趣的内容。

\n
    \n
  1. \n

    可以点击项目的 Watch 按钮来订阅消息。具体用法请看 Github - 查看订阅
    \nwatch-discussions

    \n
  2. \n
  3. \n

    也可以只订阅某个讨论。进入某个讨论,点击右边 Notifications 的 Subscribe 按钮。

    \n

    用户可以在 https://github.com/notifications 里看到订阅的新消息。

    \n
  4. \n
\n\n

👋 Welcome!

\n

We’re using Discussions as a place to connect with other members of our community. We hope that you:

\n
    \n
  • Ask questions you’re wondering about.
  • \n
  • Share ideas.
  • \n
  • Engage with other community members.
  • \n
  • Welcome others and are open-minded. Remember that this is a community we
    \nbuild together 💪.
  • \n
\n

To get started, comment below with an introduction of yourself and tell us about what you do with this community.

\n\n

本仓库谈论说明

\n

这里所有的 Discussion Format 都是 Announcement:Only maintainers and admins can post new discussions in these categories, but anyone can comment and reply.
\nDiscussion Format

\n

使用讨论 (Discussion)

\n

搜索讨论

\n
    \n
  • 版块搜索:在 Discussions 页面的搜索框输入搜索词即可。
  • \n
  • 全局搜索:在最上面的 Github 搜索框输入 org:shenweiyan 搜索词 就能搜索所有版块的讨论。比如搜"生信"
  • \n
\n

排序讨论

\n
    \n
  • 可以按时间来排序讨论。
    \nsort-discussions
  • \n
\n

使用 Label 筛选讨论

\n
    \n
  • \n

    Label 是可以无限加的。一个讨论可以有多个 Label。
    \nfilter-labels

    \n
  • \n
  • \n

    标记 Label 的好处在于,用户可以在讨论列表里筛选、多选、反选 Label 对应的讨论。
    \nfilter-by-labels

    \n
  • \n
\n

评论

\n

评论有两种。一种是在别人的评论下继续回复评论。一种是最底下的评论框,这会回复到主线里。

\n

如果你针对某个评论进行回复,建议在别人的评论下回复,不要回复到主线。这样其他订阅这个讨论的人不会收到消息提醒的干扰。

\n

讨论管理

\n

讨论分类

\n

讨论分类由项目管理员维护。按需创建。分类根据名称排序。所以加个数字前缀用来控制显示顺序。

\n

删除讨论

\n

点进讨论详情页,在右侧最底下有个 delete discussion。

\n

迁移讨论

\n
    \n
  • \n

    Transfer this discussion 功能可以把讨论移到同组织的另一个项目下。
    \ntransfer-discussion

    \n
  • \n
  • \n

    也可以切换讨论分类。
    \nchange-category

    \n
  • \n
\n

置顶讨论

\n

在讨论详情页面可以选择置到项目 Discussion 的顶部,或者置到讨论分类的顶部。
\n置顶讨论

\n

周报月报

\n

可以考虑使用 Github Action 自动跑脚本,通过 Github API 来获取 Discussion 的消息。然后自动创建 release,把简报内容写到 release body 里。这样订阅了项目 release 的人就可以收到。 可以单独创建一个项目来管理,避免订阅的人受到干扰。

\n

Github Discussion API:

\n\n

数据备份

\n

可以考虑使用 Github Action 自动跑脚本,通过 Github API 来获取 Discussion 的消息。

\n

移动端

\n

Github 有移动端 App。除了不支持 Polls 功能,其他功能都挺好用的。能查看提醒,也能发布新讨论,也能回复评论。

\n

邮件端

\n

消息提醒同时会发到你绑定的邮箱里。你也可以用邮箱来查收。

\n

博文中加评论

\n

借助 giscus,可以非常方便在文章页中插入指定的 discussions —— 在导出 discussions 的时候,在文章尾部增加类似以下 JavaScript 即可:

\n
<script src="https://giscus.app/client.js"\n        data-repo="shenweiyan/Knowledge-Garden"\n        data-repo-id="R_kgDOKgxWlg"\n        data-mapping="number"\n        data-term="4"\n        data-reactions-enabled="1"\n        data-emit-metadata="0"\n        data-input-position="bottom"\n        data-theme="light"\n        data-lang="zh-CN"\n        crossorigin="anonymous"\n        async>\n</script>
', 'author': {'login': 'shenweiyan'}, 'category': {'name': '公告说明'}, 'labels': {'nodes': []}, 'comments': {'nodes': []}}]} \ No newline at end of file diff --git a/update.log b/update.log index 23efb8d312..f476993dc0 100644 --- a/update.log +++ b/update.log @@ -1 +1 @@ -Add Changes By GitHub Actions: 2024-11-09 03:03:21 (CST/UTC-8) +Add Changes By GitHub Actions: 2024-11-10 03:02:48 (CST/UTC-8)