3

 目的

我对笔记的执念一直很深,早在上学时,每门课程都有专门的笔记本,摘录一些课程笔记、学习总结等。工作之后,需要记录和学习的知识大幅增长,光用纸笔已经远远不够用了。此时,一些笔记效率软件又帮了我大忙。尤其以 Evernote 为最,曾经一度是它最忠实的拥簇,并把它推荐给了身边的很多朋友同事,以及把个人记笔记的习惯和方式拆解,分享给他们。在我看来,一个人的学习力,很大程度上影响一个人的工作能力。而学习力的提升,最重要的一点,是需要思考学习方法,并辅之以持之以恒的学习习惯。就拿记笔记来说,同样是纸笔,有些人在上面画满了一些脑图,有些人在上面条理清晰地罗列各种知识点。前者是把知识消化后创造出来的呈现方式,而后者是井然有序地把知乎平铺在纸上,方便日后查阅。条条大路通罗马,只要你的习惯满足于当前的知识增长,就可以了。若遇到瓶颈,就需要思考新的学习方法,培养新的习惯。

在以前,Evernote 完全满足于当时的我对知识的渴求,我会把一些重要的概念和好的代码分技术别类随时随地地整理在上面,它的全文检索功能让我在工作中随时可以查阅过去的笔记,大大提升了我的工作效率。而且在反复查阅的过程中,我对概念的理解也会更深刻些,慢慢从菜鸟变成一个经验型选手。但随着自己学习的知识越来越广,这种方式已经不适合我了。因为我不但要求能做到日后随时查阅,更希望在这短暂的学习时间,能尽量地把握精要,最好一次性就能弄懂,避免日后反复去学习。而要达到这种状态,就需要时刻践行学习的 feedback loop,先 build(建立知识的概念),再 measure(检验,尝试编码或解释给别人听),最后才是 learn(文字总结),如此反复执行,内化的知识也会螺旋式上升。在这里,笔记总结承担着最关键的作用,总结学习成果,产生新的问题。所以,我思考了新的笔记想法,主要有以下几点:

  • 有良好的伸缩性,小到碎碎念,大到阅读笔记,都能支持。
  • 上面的知识点可以反复添加、重组,井然有序,并且不断自增长。
  • 支持随时随地访问,可以把笔记转成 pdf 放在 ipad 上在地铁上翻阅,也能构建成 web 页面,只要有网络的地方就能翻阅。

 工具集

  • vscode + markdown Preview Enhanced + markdownlint

    这是笔记的编辑和预览工具。笔记的源格式是 markdown 格式。先在 github 上建一个 repo,按知识分类创建一个个目录,每当想记录一个知识时,去往专门目录开一个新 md(或者找到知识关联的 md)开始记录。边思考边记录,不用太拘泥于格式(md 上也就几种常用的分段格式)。

  • pandoc + Makefile + chrome-headless-render-pdf + gitbook

    这是我的编译系统,用于表现层,把我记录的笔记转换成 html,epub 或者 pdf。makefile 把这些编译工具胶合起来。

  •  git + github + (travis + netlify)

    版本控制和存储系统, 如果你还想省事,可利用 travis 自动构建 html 发布到 netlify 上,这样就能随时随地访问了。

 实例

先在 github 上创建一个 repo,比如 my_notes,然后在该目录下创建以下文件

GITBOOK = ./node_modules/.bin/gitbook
GEN_SUMMARY = build_summary.sh

push:
    git add .;git commit -m "new note.";git push origin master:master

all: build
    @echo "TODO"

init: install dep
    @echo "Initializing the repo..."

install: 
    @echo "Install software required for this repo..."

dep:
    @echo "Install dependencies required for this repo..."
    @npm install gitbook-cli
    @${GITBOOK} install

pre-build:
    @echo "Running scripts before the build..."

post-build:
    @echo "Running scripts after the build is done..."

build: gen-summary
    @echo "building ..."
    @${GITBOOK} build

gen-summary:
    @echo "Create summary page"
    @sh  ${GEN_SUMMARY}

.PHONY: push build gen-summary init all

这个例子中,我是把 md 文件转成 gitbook, gitbook 需要有个 book.json 配置辅助编译,比如下面这个,我琢磨搭配的效果就很赞

{
  "title": "个人笔记",
  "description": "建立自己的知识脉络,方便记忆、索引、分享",
  "language": "zh-hans",
  "plugins": [
    "page-footer-ex",
    "-lunr",
    "-search",
    "-sharing",
    "-highlight",
    "search-pro",
    "expandable-chapters-small",
    "theme-comscore",
    "code",
    "custom-favicon",
    "hide-element",
    "prism"
  ],
  "pluginsConfig": {
    "theme-default": {
      "showLevel": true
    },
    "fontSettings": {
      "family": "serif",
      "size": 2
    },
    "hide-element": {
      "elements": [
        ".gitbook-link"
      ]
    },
    "favicon": "assets/book.ico"
  },
  "styles": {
    "website": "styles/website.css"
  }
}

同时,执行 gitbook build 时,它会读取一个 SUMMARY.md 文件,利用它构建页面的目录结构,由于笔记变更频繁,我们可以写个 shell 脚本,自动生成 SUMMARY.md 文件,也就是 makefile 中的 build_summary.sh。

#! /usr/bin/env bash

IGNORE_DIRS=("_book" "node_modules" "assets" )

function build_sub_categories() {
  # shellcheck disable=SC2045
  for file in $(ls $1); do
    if [ "${file##*.}"x = "md"x ]; then
      title=$(awk 'NR==1 {$1=""; print $0}' "$1/${file}")
      echo "- [${title}]($1/${file})" >> SUMMARY.md
    fi
  done
  echo "" >> SUMMARY.md
}

function build_categories() {
  # shellcheck disable=SC2045
  for file in $(ls $1); do
    if [ -d "$1/$file" ]; then
      # shellcheck disable=SC2076
      if [[ ! " ${IGNORE_DIRS[*]} " =~ " ${file} " ]]; then
        echo "## ${file}" >> SUMMARY.md
        echo "" >> SUMMARY.md
        build_sub_categories "$file"
      else
        echo "IGNORE $1/$file !!!"
      fi
    else
      echo "IGNORE $1/$file !!!"
    fi
  done
}

######### generate SUMMARY.md #########
rm -rf SUMMARY.md
echo "# Summary" >> SUMMARY.md
echo "" >> SUMMARY.md
echo "" >> SUMMARY.md
echo "- [说明](README.md)" >> SUMMARY.md
echo "" >> SUMMARY.md

这里有个小细节,为了简单,文章的 title 取得是 md 文件中的首行,所以,如果你想直接用,以后你的 md 文件首行必须有个标题,比如 ## 我的标题 这种格式。事实上,最佳实践是每个 md 头部都应该带上一个 front-matter,也是 hexo 推荐的方式,把标题、日期、作者信息放到 front-matter 区块,利用 yaml/json 等工具提取出来。

最后,我们在 my_notes 这个 repo 下创建一个笔记目录,比如 network,在 network 里面开一篇 tcp 学习记录.md,再执行下 make (需提前安装 npm 环境、gitbook),会在该 repo 下生成一个 _book 目录,该目录即是可发布的 html 目录,我们可以用 nginx 托管一下

server {
    listen 4001;
    
    root /xxxx/html/my-notes/_book;
    index index.html index.htm;

    location / {
        try_files $uri $uri/ = 404;
    } 
}

最后,写个定时任务脚本,每隔 2 分钟巡检一次 git commit,一但有变更就自动构建 _book 目录。

git pull origin master

LATEST_VERSION=`git log --pretty=format:'%h' -n 1`
VERSION=version
REFRESH=false


if [ -f ${VERSION} ];then
    if [[ $(cat ${VERSION}) != ${LATEST_VERSION} ]];then
        echo ${LATEST_VERSION} > ${VERSION}
        REFRESH=true
    fi
else
    REFRESH=true
fi

if [[ ${REFRESH} == true ]];then
    echo "new commit, refresh _book !!!"
    make build
else
    echo "no commit."

crontab 的任务如下:

*/2 * * * * cd /home/liufuyun/html/my-notes;/bin/sh check.sh > check.log 2>&1 

你可以在你学习工作电脑上写笔记,然后在你的服务器上拉取这个 repo,并按上面方式部署。部署一次后,就可以愉快地写笔记了。

以上只是简单举例, 但是思想都是一致的,不管是利用 pandoc 还是 gitbook 编译,或者利用 crontab 还是 travis 自动构建,最终都是为了方便自己,因为越是简单方便的环境越容易养成习惯。

欢迎大家留言,或者一起交流更好的笔记方法,共同学习。


未央
14 声望5 粉丝

计划|执行|精进