修复 Ubuntu 丢失的引导

今天工作的电脑因为长时间没有关机,重启了一下之后发现竟然无法启动,显示 no bootable device。大概率是因为更新的时候把 Ubuntu 的 GRUB 给更新坏了。

纯手工

首先需要通过可以启动的 U 盘系统开机,然后使用 grub-install 来安装 GRUB:

fdisk -l
sudo blkid
sudo mount /dev/sda1 /mnt
sudo grub-install --boot-directory=/mnt/boot /dev/sda

使用 boot-repair 工具一键修复

先使用 USB Ubuntu 系统,从 USB 启动系统,然后在上面安装工具 boot-repair 工具:

sudo apt-add-repository ppa:yannubuntu/boot-repair
sudo apt update
sudo apt-get install boot-repair -y

然后启动 boot-repair 自动找到对应的硬盘进行修复。

推荐使用这种方式进行修复。

在 Windows 上有一个类似的工具叫做:EasyBCD

半自动

修复完成之后再复盘之前的错误,大概率是因为我的系统是 Clonezilla 从之前的硬盘中拷贝过来的,所以我的引导分区在另外一块硬盘之上,但是更新系统的时候将这块引导分区给更新坏了。

# backup
dd if=/dev/sda2 of=$HOME/sda2.dd

#wipe it
dd if=/dev/zero of=/dev/sda2

2020-10-15 linux , ubuntu , grub , boot-loader

阿里云函数计算 fun cli

大部分的资料来自于 GitHub 页面。

安装

安装 npm,并执行:

npm install @alicloud/fun -g

配置

两种方式对 fun 进行配置,

.env 配置文件

在项目 template.yml 文件所在目录,新建 .env 文件,并配置:

ACCOUNT_ID=xxxxxxxx
REGION=cn-shanghai
ACCESS_KEY_ID=xxxxxxxxxxxx
ACCESS_KEY_SECRET=xxxxxxxxxx
FC_ENDPOINT=https://{accountid}.{region}.fc.aliyuncs.com
TIMEOUT=10
RETRIES=3

fun config 命令

执行 fun config 进行 Account ID、AccessKey ID、AccessKey Secret、Default Region Name 配置,完成配置操作后,Funcraft会将配置保存到您目录下的.fcli/config.yaml文件中。


2020-09-26 aliyun , fun , cli

阿里云函数计算中使用 Python psycopg2 访问 PostgreSQL

在之前的文章中提到过 函数计算 但一直没有正式的用起来,现在正好通过在阿里云函数计算中连接访问 PostgreSQL 来系统性的学习一下阿里云的函数计算。 首先要了解的几个概念:

  • Fun,Fun 命令是阿里提供的一个用于本地编译,部署函数计算的命令行工具,通过编写本地的 template.yml 配置文件可以对函数计算的服务, 方法, 网关 进行管理。更多内容可以参考官方提供的文档

Fun 命令简单使用

fun 命令的安装可以参考官方的文档.

配置 fun:

fun config

这里需要填写账号相关的信息。执行后会将账号相关的信息保存到:

`~/.fcli/config.yaml`

初始化项目模板:

fun init -n demo

fun 命令的执行依赖于 template.yml 配置文件。

本地调试:

fun local invoke

部署函数:

fun deploy

上传应用

上传应用方式:

  • 控制台
  • fun 工具

连接 PostgreSQL 数据库

项目依赖 template.yml 配置,配置函数计算的服务名,函数名,触发方式等等。

创建 Funfile 文件,安装依赖:

RUNTIME python3
RUN fun-install pip install psycopg2

然后执行 fun install

reference


2020-09-23 function-compute

Mac OS 上的平铺窗口管理工具 yabai

yabai 是一个 Mac OS 上的平铺窗口管理工具。Linux 上很早就有一系列的平铺窗口管理工具,比如 i3, awesome 等等。yabai 将这个功能带到了 Mac 上。所谓的平铺式窗口管理,是相较于普通的浮动窗口管理,在通常使用的情况下,系统上的应用如果打开了很多,就不可避免的相互叠加,需要频繁的使用 ⌘+Tab 来切换窗口。而平铺式窗口管理,则将所有的窗口平铺在桌面上,窗口之间不会相互重叠。

为什么要用平铺式窗口管理

在不了解平铺式窗口管理之前,我个人非常厌烦的一个事情就是不停地在不同的窗口之前切换,并且切换的效率非常低,虽然在 Mac 上有 Contexts 这样的软件来间接的提高窗口切换的速度,但是 Contexts 也需要一个模糊的查找来定位到需要切换的窗口。后来又发现了 Karabiner, 发现可以通过定义组合快捷键来快速切换到对应的应用,比如我定义了 oc 切换到 Chrome,ob 切换到 Obsidian, ok 切换到 kitty,这使得我在任何一个应用中都可以按下 o, 然后迅速的按下 c/b/k 等等来跳转到对应的窗口,即使这个应用窗口在后台,或者这个应用都没有开启,也会打开这个应用后将光标定位到该应用窗口。但这种情况下窗口大小的管理问题便随之而来,虽然我也用 Hammerspoon 定义了快捷键可以全屏,左右上下半屏,但窗口管理的其他一些问题还是没有得到进一步的改善,比如将窗口移动到第二个桌面,将窗口移到左边的显示器等等问题。

而平铺式的窗口管理,通过强可定制的快捷键将这些操作都固化成一定的动作,在熟悉这一些动作之后可以明显的提高效率,从窗口管理的麻烦中解脱出来。平铺式的窗口管理通常有如下特点:

  • 高度可定制化的快捷键动作,一般的平铺窗口工具都会提供比如切换活动窗口,最大化 / 最小化,调整大小,切换桌面,移动到其他显示器等等动作,通过这些动作和自定义的快捷键的绑定就可以实现一套自己的工作流,更甚至可以直接抛弃鼠标
  • 无需烦恼窗口的布局,在平铺式窗口管理下,窗口与窗口之间不会重叠,所有的窗口平铺在桌面上自动进行布局,再也不用担心窗口叠加切换的问题,但习惯了浮动窗口的用户可以一开始并不习惯,但如果使用久了之后就能摸索出一套属于自己的布局,利用一些快捷键可以立即进入该布局,在使用过程中也可以以 O(1) 的复杂度直接找到对应的窗口,切换窗口再不是问题

安装

如果要让 yabai 正常工作,需要 关闭系统完整性保护 System Integrity Protection,然后通过官网的教程 直接进行安装。

brew tap koekeishiya/formulae
brew install yabai
sudo yabai --install-sa

skhd 用于给 yabai 提供快捷键支持。

brew install koekeishiya/formulae/skhd

如果有其他的键盘映射工具,比如 Hammerspoon, Karabiner 也是可以的。

如果要调试 skhd 可以在安装时:

brew install skhd --with-logging

然后 skhd 就会将错误日志打印到 /usr/local/var/log/skhd/skhd.err.log 下。

配置

yabai 的 wiki 已经解释了大部分的配置选项。

yabai 会自动加载 ~/.yabairc 配置文件。

配置的格式:

yabai -m <category> <command>

在配置调试阶段,不可避免的会需要多次加载 yabairc 配置,如果每次都要重启 brew services restart yabai 太慢了,yabai 提供了重新加载的方法,执行 :

launchctl kickstart -k "gui/${UID}/homebrew.mxcl.yabai"

也可以绑定快捷键

# e.g. bind to key in skhd:
# ctrl + alt + cmd - r : launchctl kickstart -k "gui/${UID}/homebrew.mxcl.yabai"

因为我自己的常用的快捷键是 hyper+r 重新加载 hammerspoon 的配置,所以改了一下 hyper+r 不仅重新加载 hammerspoon 配置,也重新加载 yabai 配置。

模式切换

koekeishiya 的配置为例:

# change layout of desktop
ctrl + alt - a : yabai -m space --layout bsp
ctrl + alt - d : yabai -m space --layout float
ctrl + alt - s : yabai -m space --layout $(yabai -m query --spaces --space | jq -r 'if .type == "bsp" then "float" else "bsp" end')

说明:

  • ctrl + alt - a 就是平铺窗口模式
  • ctrl + alt - d 就是浮动窗口模式
  • ctrl + alt - s 切换模式

使用者可以定义任何自己习惯的快捷键来替换这一套配置。

管理多个 Display 显示器

在显示器之间切换,显示器的编号可以在系统偏好中查看。

# Focus display focused before the current one (so you can alternate)
yabai -m display --focus recent

# Focus previous display by arrangement index
yabai -m display --focus prev

# Focus next display by arrangement index
yabai -m display --focus next

# Focus display with arrangement index 2
yabai -m display --focus 2

Space

Space 指的是系统的不同虚拟桌面,yabai 可以快速的对不同的桌面进行管理。

将焦点放到不同的 Space 上

alt - 1 : yabai -m space --focus 1
alt - 2 : yabai -m space --focus 2
alt - 3 : yabai -m space --focus 3
alt - 4 : yabai -m space --focus 4

窗口管理 Windows

yabai 默认会使用二分的方式来划分窗口,一个窗口时会全屏,两个窗口时会左右对半,三个时会上下切分左边半个,依次类推。

切换活跃窗口

下面的配置是将光标定位到同一个 Space 的不同窗口上。这个操作比较常见,使用 option 作为 modifier。切换活跃窗口的操作还是非常频繁的。

# focus window
alt - j : yabai -m window --focus south
alt - h : yabai -m window --focus west
alt - k : yabai -m window --focus north
alt - l : yabai -m window --focus east

这些定义分别对应着使得,j(下方), k(上方), h(左侧), l(右侧) 的窗口成为活跃窗口。

交换窗口的位置

alt + shift - j : yabai -m window --swap south
alt + shift - h : yabai -m window --swap west
alt + shift - k : yabai -m window --swap north
alt + shift - l : yabai -m window --swap east

同样可以定义如何移动窗口

shift + cmd - h : yabai -m window --warp west
shift + cmd - j : yabai -m window --warp south
shift + cmd - k : yabai -m window --warp north
shift + cmd - l : yabai -m window --warp east

调整窗口大小的操作我用的很少,有需要可以使用。

# move window
shift + ctrl - a : yabai -m window --move rel:-20:0
shift + ctrl - s : yabai -m window --move rel:0:20
shift + ctrl - w : yabai -m window --move rel:0:-20
shift + ctrl - d : yabai -m window --move rel:20:0

# increase window size
shift + alt - a : yabai -m window --resize left:-20:0
shift + alt - s : yabai -m window --resize bottom:0:20
shift + alt - w : yabai -m window --resize top:0:-20
shift + alt - d : yabai -m window --resize right:20:0

# decrease window size
shift + cmd - a : yabai -m window --resize left:20:0
shift + cmd - s : yabai -m window --resize bottom:0:-20
shift + cmd - w : yabai -m window --resize top:0:20
shift + cmd - d : yabai -m window --resize right:-20:0

开关窗口的浮动模式

alt - t : yabai -m window --toggle float && yabai -m window --grid 4:4:1:1:2:2

开关 picture-in-picture 模式

alt - p : yabai -m window --toggle border && \
          yabai -m window --toggle pip

Status bar

我个人将桌面上除了窗口以外的所有状态栏等等都隐藏了,如果要添加自定义的内容可以选择:

stackline

stackline 是 yabai 的一个增强,在窗口的 stack 模式上增加了一层可视化的显示,一个 stack 会在左上角的地方显示当前这个 stack 中的应用列表。

参考配置

reference


2020-09-17 mac , tiling-window-manager , window-manager , hammerspoon

macOS 上好用的截图工具

macOS 自带

  • ⌘+Shift+3 截取整个屏幕
  • ⌘+Shift+4 截取部分屏幕,按下快捷键之后选择
  • ⌘+Shift+5 打开截图应用,在应用中可以选择截图、录制视频等
  • ⌘+Shift+6 截取 Touchbar 的屏幕
  • ⌘+Shift+Ctrl+4 截取屏幕并保存到粘贴板
  • ⌘+Shift+4+space 截取某个窗口或菜单

macos screenshots shortcut

shottr

shottr 是一款 macOS 上的截图工具,支持部分,全屏,窗口,滚动截图。shottr 还支持文字打码。

我沿用之前的习惯:

  • F1 部分截图
  • Cmd+Shift+F1 截取窗口

Snipaste

[[Snipaste]] 是一款跨平台的截图工具,使用 QT 构建。

iShot

iShot 是一款 macOS 上的截图工具,支持长截图,OCR,标注等等功能。

  • 可以在图片上进行标注步骤(数字)
  • 可以高亮显示截图中的部分内容,其他内容使用灰色
  • OCR
  • 截长图

Jietu

Jietu 是腾讯推出的截图工具。

CleanShot X

CleanShot X 是一款收费的截图工具。

  • 截图后的图片编辑器
  • CleanShot Cloud,一键上传图片
  • 滚动截图

一次性付费 29$ 可以到的软件及 1GB 的 Cloud 空间。也可以选择月付费 10$,或者年付费,获得无限空间,自定义域名等服务。

reference

  • [[Mac 快捷键]]

2020-09-10 macos , screenshot , snipaste , shottr , record

You Quiz on the Block E70 世代差异

Covid-19 以来很少有让我继续追下去的韩综,除了带我入坑的周末综艺,一个 《[[Begin Again Korea]]》剩下的就只有《You Quiz On the Block》了。可以看得出来韩国的综艺人,电视人总还是带着一些社会关怀再做内容,之前在《Begin Again》里面就提过,在这个特殊的时代,他们把歌声第一时间先给一线的医护人员,公共服务人员,在这个疫情的特殊时期《Begin Again》就是一个治愈的存在,而相同的《You Quiz》第三期开篇就是对社会一线人员的致敬,公交司机,私营店老板,快递员,防疫人员,社会正是在这些人继续工作下去的时候才能维持正常的运行。

而在第三季的《You Quiz》中因为受到疫情影响,节目形式进行的改变,从原来街头的随机采访变成了主题式的室内采访,我甚至觉得这个模式似乎更有看点,主题也分外的明显,显而易见的比之前的模式要更加有中心主旨。虽然以前也会用一两个相同的问题来串起一个 Episode,但相较于现在而形式,也显得比较散。

再回到 E70,这一期的主题是世代差异。节目组分别邀请了 Z 世代,Y 世代,X 世代,386 世代,产业化世代 5 代人来讲述不同世代的故事。这一期的节目就像是一部倒放的韩国近代史。一直从 2000 年讲述到了上世纪 50,60 年代,当然叙事的方式并不是大而全的通用叙事,而是更加具体的从个人视角发出的主观的历史叙事。我作为千禧一代 (Y 世代)出生的人,最感同身受的却是 X 世代,或许另一个角度也能看出两个国家发展阶段的不同。

另外一个能察觉到节目组用心之处的便是节目的音乐,虽然韩综的配乐一直是长项,但这样的一个主题下,便更能体现其年代感,每一个世代所接触到的音乐,所关心的音乐人都不一样。生活在 2000 年以后 Z 世代是随手可得的音乐,Y 世代是放在自己的网络小屋的背景音乐,是自己的在庆典上偶像的歌曲,在到 X 世代是弘大,是夜店的歌曲,386 世代而言,音乐要珍贵许多,要守在广播前等待自己喜欢的歌手出现,再用录音机把歌声录下(杨熙恩,宋昌植)(采访的对象提到的杨熙恩 양희은 也是我非常喜欢的一位歌手,在 [[Fantastic Duo]] 短暂出现过),到更早一代,只能在异国他乡独自一人的晚上收听唯一的一档韩语广播。每一个世代都有自己喜欢的音乐,而有些音乐不像那个时代被一代人熟知,也依然可以穿过时间,直达现在每一个观众的内心,尤其是看那位远赴德国务工的老爷爷哼唱出《阳光明媚的日子 (해뜰날 by 송대관)》:

꿈을안고왔단다 抱着梦想来了 내가왔단다 我来了 슬픔도괴로움도 悲伤与伤心 모두모두비켜라 统统都让开 안 뒤는 일이없단다 有志者 노력하면은 事竟成 쨍하고해뜰날 阳光明媚的日子 고구간단다 回到故国 쨍하고해뜰날 阳光明媚的日子 고구간단다 回到故国

这几句歌词出来,直抵人心。音乐无论在哪个年代,虽然会以不一样的形式出现,虽然会被不一样的歌手所演绎,但总能给人以慰藉,这或许也是我独爱《Begin Again》的理由吧。

抛开音乐回到这几代人对历史时刻的最深记忆,而这些历史事件也逐渐的塑造了如今的韩国。从远到近说起。

  • 1963 年后陆续派遣近两万名劳工赴德国务工,电影 [[国际市场]] 中有讲述
  • 朴正熙政权在 1961 年至 1979 举国之力发展工农业,史称「汉江奇迹」,1979 年 10 月 26 日,朴正熙被中央情报部部長金载圭暗杀,电影 [[南山的部长们]] 有讲述,另 [[孝子洞理发师]] 1
  • 1980 年 5.18 光州民主化运动 [[出租车司机]] [[华丽的假期]] [[薄荷塘]]
  • 1987 年 6 月民主抗争,朴种哲事件,李韩烈事件 [[1987 黎明到来的一天』]
  • 1994 年 [[圣水大桥倒塌事件]] 电影 [[蜂鸟]] 中有提及
  • 1995 年 6 月 29 日 [[三丰百货大楼崩塌事故]],502 人死亡,6 人失踪,937 人受伤
  • 1997 年 12 月 3 日,向 [[IMF 申请金融救济』] 电影 [[国家破产之日]] 讲述的就是这一段历史
  • 2014 年 [[世越号事件]],已经有无数的电影来铭记这件事情 [[潜水钟]] [[那天,大海]]

大多数的历史性事件已经有大量的电影,进行了更加详细的记录和阐述。而现在的采访才更加有价值,事件的亲历者,亲自讲述那段苦难,虽然现在能笑着说出来,但背后却不知道隐藏了多少泪水。赴德国的老爷爷讲述第一次面试举麻袋失败后在家练习,亲历 1987 年 6 月运动后讲述为后辈捡起掉落的鞋子,却不料是最后一别。不禁让我感慨现实有的时候远比电影要残酷。老爷爷最后回答人生是什么的时候说,「人生是艺术」,不为过,也确确实实可以形容了。

Z 世代

  • 2000 年后出生,现在 10 代的青少年们
  • 不看文本,看视频
  • 不用电脑,用手机
  • 产品的生产者与消费者
  • 在数字环境下成长的数字原住民

唠叨会让人不爽,忠告会让人更不爽。

Y 世代

  • 又被称为千禧一代,指 1980 年代和 1990 年代出生的人
  • 2014 年世越号事件

X 世代

X 世代

  • 是指出生与 1960 年代后期到 1970 年代之间
  • 在人类历史上唯一同时经历过数字和模拟的一代人
  • 拒绝老一代的习俗和秩序,用全身拒绝已存在的条条框框,个性分明的一代人
  • 享受了 90 年代经济上升,生活富足的第一代人

经历事件:

  • 1994 年 [[圣水大桥倒塌事件]] 电影 [[蜂鸟]] 中有提及
  • 1995 年 6 月 29 日 [[三丰百货大楼崩塌事故]],502 人死亡,6 人失踪,937 人受伤
  • 1997 年 12 月 3 日,向 [[IMF 申请金融救济』] 电影 [[国家破产之日]] 讲述的就是这一段历史

386 世代

386 世代是在 60 年代出生,在 80 年代上大学,在 90 年代是 30 多岁的世代。当时的电脑架构是 386,还是 486 的,还是奔腾的,这个时候登场的 386 世代。这是一个象征着当时主导抵抗军事政权的学生运动和工人运动等社会运动的世代。

[[柳烈的音乐专辑]] 中

电影 [[1987 黎明到来的一天』] 中有大量描述。

产业化世代

1945 年光复之后,韩国战争期间出生的世代。1960~1970 年代,游走世界,掀起产业发展,创造出「汉江奇迹」,大韩民国经济成长的主力,称之为「产业化世代」。 电影 [[国际市场]] 有讲述。

  1. https://en.wikipedia.org/wiki/Miracle_on_the_Han_River 


2020-09-05 thinking

跨平台的 GPU 加速终端 kitty

之前在学习使用 dotbot 管理 dotfiles 的时候参考了不少 GitHub 上的 dotfiles 项目,发现大家都不约而同的用到了一个叫做 kitty 的终端,我个人在 Linux 上用 Guake ,在切换到 Mac 之后选择了大部分人推荐的 iTerm2,虽然用着也没有遇到问题,但一旦和 kitty 比较起来速度便成为了一个问题。

官网地址:https://github.com/kovidgoyal/kitty

为什么要换用 kitty?

之前使用的 [[Guake]], iTerm 自身也并没有什么问题,但近两年来越来越喜欢纯文本的配置,这样就可以放到 dotfiles 中进行追踪,并且跨平台也只需要同步一下配置即可,Guake 和 iTerm 在各自的平都是非常不错的选择,但都不是跨平台的选择。所以综上这些原因,让我有了尝试一下 kitty 的动力。

kitty 的一些特性:

  • 跨平台,日常在 Linux 和 macOS 之间切换,我希望配置一遍就可以在不同的平台上使用。
  • 纯文本的配置,理由同上
  • GPU 渲染,肉眼可见的速度提升

配置

kitty 默认的配置文件在 ~/.config/kitty/kitty.conf,可以将这个文件拷贝到 dotfiles 仓库中管理,然后用软链接链过去。kitty 默认不支持热加载配置文件 1,所以每一次修改配置都需要退出重进。具体的配置可以参考我的 GitHub

调试 kitty 的配置可以使用 kitty --debug-config,执行这行命令会将 kitty 当前的配置,以及加载的配置都打印出来。kitty 配置的各个选项在 kitty 的文档中已经非常详细的记录了。

include 其他配置

include other.conf

配置 Fira Code 字体

自从发现了 Fira Code 字体已经用这一款字体很多年了。但是在 kitty 上使用时,Fira Code 字体总是在一行的偏上部分,这已经很多人反馈过 2.

目前的解决办法只能是:

adjust_line_height  -3
adjust_column_width -1

配置和 Guake 类似的下拉式终端

借助 [[Hammerspoon]] 可以实现类似 Guake 类似的下拉效果。

hs.hotkey.bind({}, "F12", function()
    local app = hs.application.get("kitty")
    if app then
        if not app:mainWindow() then
            app:selectMenuItem({"kitty", "New OS window"})
        elseif app:isFrontmost() then
            app:hide()
        else
            app:activate()
        end
    else
        hs.application.launchOrFocus("kitty")
		app = hs.application.get("kitty")
    end

	app:mainWindow():moveToUnit'[100, 80, 0, 0]'
	app:mainWindow().setShadows(false)
end)

同步我之前的快捷键

我之前在使用 Guake 的时候就使用 Alt+n/p 来切换 Tab,正好键位在 Mac 上是 Cmd+n/p 用下面的代码重新 remap 一下:

map cmd+n next_tab
map cmd+p previous_tab

配色方案

reference


2020-08-27 gpu , terminal , linux , mac , guake , drop-down

使用 Goku 配置 Karabiner

Karabiner 是 MacOS 上一款强大的自定义键盘的软件,可以非常自由的定义任何键位。Karabiner 是一个开源软件,用于在 macOS 系统上自定义键盘映射。它允许用户修改键盘输入以实现更高效的使用体验。

之前看文章是将 Caps Lock 作为一个 Hyper key,但看过 @nikitavoloboev 的文章之后,发现利用 Karabiner 和 Goku 定义的 DSL 配置语言可以更加充分的发挥 Karabiner 的功能。

Karabiner Elements 使用 JSON 作为配置规则的格式,但是使用 JSON 作为 Karabiner 配置格式的问题在于 JSON 格式非常庞大冗余,在生成之后几乎很难徒手去做修改,对于复杂的配置可能长达几万行。

所以诞生了 Goku,可以利用非常简洁的配置语法来配置 Karabiner 的 JSON 配置文件。 Goku 是一个基于 Karabiner 的配置工具,它使用了 EDN 格式来定义键盘映射和自定义操作。

前提知识

在进入配置之前需要先了解一些前提知识。

Sticky keys 粘滞键

Sticky Keys 叫做粘滞键,是方便无法同时按下 Ctrl C 这样组合按键的用户,启用粘滞键后按下任何 modifier 按键后,这个 modifier 按键会持续激活直到按下一个非 modifier 按键。

Modifier key 修饰键

常见的 modifier 按键有 Ctrl, Command, Shift, Alt, Option,Fn, Caps Lock 等等。

A keyboard feature that enables you to press a modifier key (CTRL, ALT, or SHIFT), or the Windows logo key, and have it remain active until a non-modifier key is pressed. This is useful for people who have difficulty pressing two keys simultaneously.

其他可作为 modifier key 的按键有:

  • \
  • ,
  • .
  • space
  • Tab

EDN

EDN 全称是 「extensible data notation」,是一种用于表示数据的轻量级文本格式。它的语法类似于 Clojure 语言的数据结构表示法,可以用于序列化和传输数据。

下面是一个最基本的 EDN:

{:main [
  {:des "hello world"
   ; comments use semicolons
       :rules [
      [:a :b] ; map a key to b key
   ]}
]}

不用担心这里看不明白,后面会继续展开。上面的配置及时目前看不明白,可以大致了解到,是一条自定义的规则,描述和具体的 rule ,将按键 a 映射到 按键 b。

什么是 Karabiner

[[Karabiner Elements]] 是一个 MacOS 上的键盘自定义工具。

定义第一个 Hyper key

准备工作:

  • 下载 Karabiner Elements
  • 安装 Goku (Karabiner DSL) brew install yqrashawn/goku/goku
  • 执行 goku 服务,让修改立即生效 brew services start goku
  • 打开 Karabiner
  • 然后在 ~/.config/ 目录下创建 karabiner.edn 文件,可以参考我的
  • 然后可以参考教程 开始自己的配置编写啦

Goku 会通过 EDN 文件生成 karabiner.json,编写好 edn 文件后可以执行 goku 来生成 JSON 配置。

基本使用

安装 Goku

brew install yqrashawn/goku/goku

安装之后配置文件默认位置在 ~/.config/karabiner.edn 但是可以使用环境变量 GOKU_EDN_CONFIG_FILE 自定义配置路径。

服务其中之后,日志在 ~/Library/Logs/goku.log ,任何错误都可以查看。

完成安装之后可以运行 goku --version 来查看版本。可以使用 gokuw 来持续监控配置文件生成 karabiner.json

重启服务

brew services restart yqrashawn/goku/goku

查看服务配置

less ~/Library/LaunchAgents/homebrew.mxcl.goku.plist

配置

整个 EDN 配置大体可以分成几个部分:

  • 定义主要的 profile 及基本信息
  • 预置的条件
  • main 部分为主要的键映射配置

接下来就一步步看一下最简单的配置。

从最主要的 main 部分配置来看。

{:main[ {:des "..." :rules [[<from> <to> <condition>]]}
        {:des "..." :rules [[<from> <to>]
                            [<from> <to>]]} ]}
  • 花括号内整个内容表示一个规则
  • :des 部分用来注释规则
  • :rules 中是真正的规则
  • 规则又分成 from, to, condition,其中 condition 部分是可选的。

更加详细的配置可以参考我的 dotfiles

预置条件

定义应用

可以使用 bundle ID 来定义应用程序,如何查找这个 Bundle ID,可以利用 Karabiner 自带一个 EventViewer 工具,很方便地查看应用的 Bundle ID,或者右键『应用.app』-> 显示包内容 Contents/Info.plist -> BundleIdentifier 也可以查看到。

:applications {:chrome ["^com\\.google\\.Chrome$"]}

在 Karabiner EventViewer 中

U8zW

定义设备

定义设备,同样设备的 ID 也可以在 EventViewer 中查看:

:devices {:quickfire [{:vendor_id 1234 :product_id 17}]}

通常当你有外置的键盘等等设备时会使用到这个。比如当你有不同布局的外置键盘的时候,可以配合 [[Hammerspoon]] 来自动切换 Karabiner 的配置。

定义输入法

定义输入法,也可以通过应用的 ID 来配置:

     :input-sources {:squirrel {:input_mode_id "com.googlecode.rimeime.inputmethod.Squirrel"
                  :input_source_id "com.googlecode.rimeime.inputmethod.Squirrel.Rime"
                  :language "zh-Hans"}
                 :us {:input_mode_id ""
                      :input_source_id "com.apple.keylayout.US"
                      :language "en"}}

变量条件定义:

    [:escape [:escape ["in-alfred" 0]] ["in-alfred" 1]]
;;   |<from>||_________<to>__________| |<conditions> |

这一条规则表示的含义是,当变量 in-alfred 等于 1 时,tap Escape 按键映射到 Escape 并将 in-alfred 变量设置为 0 。

在使用条件的时候可以组合使用,或者使用非语句。

比如,先定义了应用,然后将预先定义的应用到规则中。

{:applications {:chrome ["^com\\.google\\.Chrome$"]
                :safari ["^com\\.apple\\.Safari$"]}
 :main [{:des "a to 1 only in chrome" :rules [[:a :1 :chrome]]}
        {:des "a to 1 only in chrome, safari" :rules [[:a :1 [:chrome :safari]]]}
        {:des "a to 1 only outside chrome, safari" :rules [[:a :1 [:!chrome :!safari]]]}]}

上面的这三条规则就是表示

  • 在 Chrome 应用中将按键 a 映射到按键 1
  • 在 Chrome,Safari 中 a 映射到 1
  • 除了在 Chrome 或 safari 中,其他应用中 a 映射到 1

或者组合使用:

:main [{:des "a to 1 multiple conditions"
        :rules [[:a :1 [:chromes :quickfire :us]]]}]}

这条规则就表示在 Chrome 中,使用外置的 quickfire 键盘,并且输入法是 us 时,将 a 键映射到 1。

有了这样的组合,就可以非常轻松地实现一个 Windows 布局键盘修改成 macOS 使用的键盘,比如将 Ctrl 映射成 Command。

组合规则

简单规则,一个键映射到另一个按键,一个键映射到多个按键

{:main [{:des "a to 1" :rules [[:a :1]]}
        {:des "b to 2" :rules [[:b :2]]}
        {:des "c to insert 123" :rules [[:c [:1 :2 :3]]]}]}

多个按键映射到其他按键,比如同时按下 j,l 映射到 F20

:rules [[:j :l] :f20]

配置也可以将按键映射到 Shell 脚本

:rules [{:des "hyper 1 to clean tmp"
                   :rules [[:!!1 ["rm -rf /tmp/*"]]]]}

对于常见的修饰键 modifier,Goku 中用简化的配置来表示

    ;; !  | means mandatory -   modifier(s) alone when pressend change behavior
    ;; #  | means optional  -   modifiers are optional (but at least one necessary)

    ;; :!Ca is keycode :a and prefix a with !C

    ;; C  | left_command
    ;; T  | left_control
    ;; O  | left_option
    ;; S  | left_shift
    ;; F  | fn
    ;; Q  | right_command
    ;; W  | right_control
    ;; E  | right_option
    ;; R  | right_shift

    ;; ## | optional any
    ;; !! | command + control + optional + shift (hyper)

说明:

  • 在不设置 mofifiers 时,键映射只有在没有 modifier 时才生效,比如定义了一条规则,将 Caps Lock 映射成 Escape,那么只有在单独按下 Caps Lock 的时候才会映射成 Escape,如果组合按键比如 Left Shift+Caps Lock(当然应该没人那么做) 的时候,表现还是 Left Shift+Caps Lock
  • 当 modifier 为 mandatory 时,只有 modifier 按下时,映射才会触发

定义模板

{:templates {:launch "osascript -e 'tell application \"Alfred 3\" to run trigger \"launch %s\" in workflow \"yqrashawn.workflow.launcher\" with argument \"\"'"}
 :main [{:des "launcher mode"
         :rules [[:k [:launch "Emacs"] :launch-mode]
                 [:l [:launch "Chrome"] :launch-mode]
                 [:m [:launch "Mail"] :launch-mode]
                 [:v [:launch "WeChat"] :launch-mode]]}]}

simlayer

定义 simlayer

:simlayers {:vi-mode {:key :d}}

上面的规则定义了如果按下了 d 按键,则设置变量 vi-mode 为 1,表示进入 simlayer vi-mode,to_if_alone dto_after_key_up 然后设置变量 vi-mode 到 0 。

配置样例

交换 Left Option 和 Left Command

当我使用外置键盘的时候交换 Option 和 Command 的按键。

首先定义一些设备:

 :devices {
    :apple [{:vendor_id 1452 :product_id 832}]
    :quickfire [{:vendor_id 9494 :product_id 17}]
  }

特定键盘更改键位,改完之后就可以和内置键盘的键位一样了,不用去熟悉两套键盘了。

可以使用两种不同的方式进行配置:

这里的 quickfire 是我的外接键盘。这些信息可以在 Karabiner 提供的 EventViewer 中查看。

然后在 main 部分定义:

        {:des "swap cmd <-> option when using specific devices"
         :rules [
                 [:##left_command :left_option [:quickfire]]
                 [:##left_option :left_command [:quickfire]]
                 ] }

或者

    {:des "CM Storm keyboard setup"
     :rules [:quickfire
                 [:##left_command :left_option]
                 [:##left_option :left_command]
             ]}

Caps lock

tap caps lock once -> Escape key
hold caps lock -> hold Ctrl+Shift+Option+Command at same time

Left Shift/Right Shift

在英文的世界中,有一种 Remap,是将

left_shift once -> type (
right_shift once -> type )

但是在中文的世界里面,我的 Shift 是作为中英文切换按键,非常重要的一个按键。

O 模式

如果经常在几个常见的应用之间切换,即使用了不错的比如 Context 这样的窗口管理工具,那也会在 Command + Tab 按键中非常频繁的按键。假如有方式可以通过按下键盘上的快捷键就可以直接切换到不同的窗口,是不是可以省去不少的烦恼。

下面是一个模式,通过按住 O,然后快速按下第二个按键就可以实现在常用的应用之间切换。

hold o + tap i -> launch "iTerm"
hold o + tap c -> launch "Chrome"
hold o + tap b -> launch "Obsidian"
tap o  -> type "o"

记住一定要按住 o 不要松开然后再按 c 就可以快速切换到 Chrome。 一旦熟悉了自己的配置,就会发现再也不需要使用 Cmd + Tab 来切换了。

将 Caps Lock 作为 Command+Control+Option+Shift 同时按下的效果

        {:des "caps lock -> escape(alone) and caps lock -> hyper"
         :rules [
                 [:##caps_lock :!CTOleft_shift nil {:alone :escape}]
                 ]}

Ctrl+np 作为上下

        {:des "Ctrl np -> down up"
         :rules [
                 [:!Tn :down_arrow [:ctrlnp]]
                 [:!Tp :up_arrow [:ctrlnp]]
                 ]}

禁用 Cmd+H 隐藏

        {:des "Disable Cmd+H Hide"
         :rules [
                 [:!Ch nil nil [:kybs]]
                 ]}

按住 Cmd+q 退出应用

在默认情况下 macOS 按下 Cmd + q 就会退出当前应用,没有任何提示,使用这个配置之后就必须同时按下 Cmd + q 一秒钟时间才会触发退出。

        {:des "Cmd + Q held 1 second to quit"
         :rules [
                 [:!Cq nil nil {:held :!Cq }]]}

Cheatsheet

    ;; !  | means mandatory -   modifier(s) alone when pressend change behavior
    ;; #  | means optional  -   modifiers are optional (but atleast one necessary)

    ;; :!Ca is keycode :a and prefix a with !C

    ;; C  | left_command
    ;; T  | left_control
    ;; O  | left_option
    ;; S  | left_shift
    ;; F  | fn
    ;; Q  | right_command
    ;; W  | right_control
    ;; E  | right_option
    ;; R  | right_shift

    ;; ## | optional any
    ;; !! | command + control + optional + shift (hyper)

    ;; to understand better how modifiers work in karabiner
    ;; karabiner definition of mandatory and optional
    ;; https://karabiner-elements.pqrs.org/docs/json/complex-modifications-manipulator-definition/from/modifiers/


    ;; need to prefix C T O S F with ! or #
    ;;
    ;; code for all this:
    ;; https://github.com/yqrashawn/GokuRakuJoudo/blob/b9b334a187379f9bc8182ad59e2cca2a1789e9c0/src/karabiner_configurator/keys.clj#L68

更多

  • 阅读 Nikita Voloboev 的博客
  • 完整的尝试官方提供的例子
  • 然后在仔细的读一读上面的例子

reference

其他配置案例:


2020-08-20 karabiner , mac , goku , edn , config

使用 dotbot 管理 dotfiles 配置文件

一直都使用手动的方式来管理 dotfiles,之前一方面是学习,一方面是熟悉整个配置,但随着配置文件的不断增多,管理便成为了一个问题。今天本来是在看 Karabiner 的配置,然后找到了一些参考,发现 narze 使用 dotbot 来管理其配置。便顺手也把我的 dotfiles 改了一下。

dotbot 的原理非常简单,就是将配置文件软链接到特定的位置,使得 Vim,Tmux, zsh 之类可以直接使用。然后 dotbot 使用 YAML 定义的一套配置格式将整个过程简化。使得最后可以直接运行 git clone git@github.com:einverne/dotfiles.git && cd dotfiles && make bootstrap 一键完成初始化。

使用

最基本的使用方法,参考说明:

cd ~/.dotfiles # replace with the path to your dotfiles
git init # initialize repository if needed
git submodule add https://github.com/anishathalye/dotbot
git config -f .gitmodules submodule.dotbot.ignore dirty # ignore dirty commits in the submodule
cp dotbot/tools/git-submodule/install .
touch install.conf.yaml

将其加入为作为 submodule 然后添加一个配置 install.conf.yaml 即可。

更新

更新子 module:

git submodule update --remote 

Configuration

dotbot 的配置文件是 yaml 格式,非常易读。这是官网给的一个例子:

- defaults:
    link:
      relink: true

- clean: ['~']

- link:
    ~/.tmux.conf: tmux.conf
    ~/.vim: vim
    ~/.vimrc: vimrc

- create:
    - ~/downloads
    - ~/.vim/undo-history

- shell:
  - [git submodule update --init --recursive, Installing submodules]

目前 Dotbot 定义了一系常用的动作,比如 link, create, shell, clean 等等。

defaults

defaults 定义了默认的行为。

link 命令定义了文件或文件夹如何 symbolically linked。

create

create 命令定义了回去创建这些目录。

shell

Shell 命令则会指定需要运行的命令。

clean

clean 命令会去检查目录下的连接,如果发现连接已经无效则会移除这些连接。

reference


2020-08-15 dotfiles , config , mac , linux , vim , zsh

使用 assh 来管理 SSH config

前两天一直在思考如何管理我的 SSH config 配置,最后的解决办法就是通过 git 版本管理起来。但这两天由冒出一个新的问题,那就是经常在国内直连 aws 或者 oracle 的机器时 ssh 连不上,但是通过国内的 VPS 中转就非常快,那这就意味着,我每一次连接国外的机器时必须先登录腾讯云的机器,然后在从腾讯云的机器上连过去,有些麻烦,但那天在 Twitter 上看到有人分享了一个 SSH 管理的命令行工具 assh,大致的看了一下使用简介,通过配置就可以完美的解决这个问题。

ProxyCommand

assh 这个工具就将登录一台机器跳转 SSH 再登录另外一台机器的步骤简化了,assh 使用 lib-ssh 提供的 ProxyCommand 来实现。大部分的公司,或者注重安全的 SSH 访问都会将 SSH 的登录配置管理放到一台堡垒机或者跳板机上,然后通过跳板机再去连接真正的机器。

 +-------+       +----------+      +-----------+
 | Laptop| <---> | Jumphost | <--> | RealServer |
 +-------+       +----------+      +-----------+

比如上面的流程中,可能需要先连接 Jumphost:

ssh -p 222 someone@Jumphost

然后在 Jumphost 上连接真正的服务器,一方面是为了安全考虑,另一方面是可以非常方便的进行权限管理和审计:

ssh someone@RealServer

如果要简化这个步骤可以使用 SSH 的 -J 选项:

ssh -J someone@Jumphost:222 someone@RealServer

或者可以使用 ProxyCommand:

ssh -o ProxyCommand='ssh -W %h:%p -p 222 someone@Jumphost' someone@RealServer

从 OpenSSH 7.3 开始,还可以使用 ProxyJump,可以通过在 config 文件中配置:

Host RealServer
    HostName 1.2.3.4
	ProxyJump someone@Jumphost:22[, user2@Jumphost2:222]
	User someone

如果有多个 Jumphost 可以直接用逗号分隔接在后面。

上面两个方式都可以直接通过 Jumphost 来直接登录到 RealServer 上。

SSH Config 配置

  • Host: 定义 host, * 可以用来表示全局配置
  • HostName: 定义真实的 hostname, 可以是域名或者 IP
  • User: SSH 登录的用户名
  • IdentityFile: 私钥路径
  • ProxyCommand: 定义连接服务器的命令
  • LocalForward: 通过 TCP 转发指定的本地端口到远程的端口
  • Port: 指定连接的远程端口
  • Protocol: 协议
  • ServerAliveInterval: 设置没有数据后多少时间间隔超时
  • ServerAliveCountMax: 设置服务活跃信息的数量,如果阈值达到,同时服务器活跃信息 ,服务器活跃消息 (server alive messages) 通过加密通道传输,因此不能被欺骗。The TCP keepalive 选项通过 TCPKeepAlive 是可以伪造的。服务器活跃机制在判断客户端或者服务器在不活跃时何时断开是非常有用的。默认值是 3,举一个例子,ServerAliveInterval 设置成 15,ServerAliveCountMax 保持默认,如果服务器没有回应,ssh 会在大约 45 秒后断开连接。这个选项只在 protocol 2 下有效

看一个最基本的 assh.yml 配置:

hosts:
  hosta:
    Hostname: 1.2.3.4

  hostb:
    Hostname: 5.6.7.8
    Gateways: hosta

  hostc:
    Hostname: 9.10.11.12
    Gateways: hostb

  hostd:
    Hostname: 13.14.15.16
    GatewayConnectTimeout: 2
    Gateways:
    - direct
    - hosta

说明:

  • 配置了 hosta 直连
  • hostb 则是通过 hosta 连接,ssh hostb 时会转换成 ssh -o ProxyCommand="ssh hostb nc %h %p" hosta
  • hostc 通过 hostb 连接
  • hostd 会首先尝试直连,如果失败了则回退到使用 hosta 连接

加速 SSH 会话

OpenSSH 可以复用存在的 TCP 连接,比如在创建了多个 SSH sessions 的时候,可以避免 TCP 创建连接带来的过度开销,修改 vi ~/.ssh/config:

Host *
	ServerAliveInterval 60
	ServerAliveCountMax 30
	ControlMaster auto
	ControlPath ~/.ssh/connection-%r@%h:%p
	ControlPersist 48h

assh

回到 assh 本身,assh 是用 Go 语言编写的一个命令行工具,使用 yaml 格式的配置,可以通过该配置快速生成 ~/.ssh/config 配置,通过几行配置就可以利用 ProxyCommand 来进行 SSH 跳转。

特性

assh 非常小巧,当却很强大

  • 支持正则表达式
  • 支持别名 aliases -> gate.domain.tld
  • 支持 includes 语法,可以将配置文件拆分到多个文件 includes: split configuration in multiple files
  • 支持 SSH 连接的透明转发 gateways -> transparent ssh connection chaining
  • local command execution: finally the reverse of RemoteCommand
  • inheritance: make hosts inherits from host hosts or templates
  • 支持继承,可以通过继承其他 hosts 或者模板来简化配置
  • templates: 模板
  • 通过环境变量来进行配置 variable expansion: resolve variables from the environment
  • 更加灵活的 ProxyCommand, smart proxycommand 当 netcat 或者 socat 可用时,会替换纯 TCP 连接
  • 可以进行速率控制,rate limit
  • JSON output
  • desktop notifications: based on events
  • Graphviz representation of the hosts

Install

如果本地安装了 Go 环境:

go get -u moul.io/assh/v2

macOS 上:

brew install assh

Event

assh 支持一些事件,可以用来触发一些操作或者进行通知。

BeforeConnect

BeforeConnect 会在 assh 将要连接到远程 SSH 端口时触发。

OnConnect

OnConnect 会在连接到远端 SSH 端口后被调用。

OnConnectError

OnConnectError 会在 assh 在建立 TCP 连接失败时调用。

OnDisconnect

OnDisconnect 会在 assh socket 断掉后触发。

BeforeConfigWrite

BeforeConfigWrite 会在 assh 重写 ~/.ssh/config 时触发。

基础命令

assh config

# 生成 SSH 配置文件
assh config build
assh config build > ~/.ssh/config
# 搜索 hosts
assh config search <keywords>

# 列出配置
assh config list
# 可视化显示
assh config graphviz

assh sockets

# 列出活跃的连接
assh sockets list
# create a master control sockets
assh sockets master
# close active control sockets
assh sockets flush

assh ping

# send packets to the SSH server
assh ping -c 4 host

reference


2020-07-28 ssh , assh , ssh-config , ssh-manage , config-management

电子书

最近文章

  • 时隔 5 年再安装 NextCloud 时隔多年,我再安装了一次 [[NextCloud]],很早之前 就在我的 QNAP TS 453B mini 上安装并使用了多年,这两年也一直在跟随着官方的版本升级 ,但是 QNAP 毕竟在局域网内,虽然可以使用 Tailscale,ZeroTier 等等工具来组件局域网,但毕竟还是不方便,最近入手一台还不错的 VPS,所以想着再搭建一个公有 IP 的 NextCloud,一方面备份一下自己的相册,另一方面也补足一下我自己使用 Syncthing时没有在线预览的页面,导致常常有些时候想访问自己的笔记而找不到。
  • 使用 SyncTV 异地远程一起看视频 因为和女朋友异地,之前我们都一直使用 [[Plex]] 来同步看视频,基本上可以做到秒级别的共享观看。今天看 GitHub 的时候发现一款叫做 SyncTV 的应用,也是可以通过同步的方式了共享观看视频流,那这样就可以一起看视频,看直播了。原来 Plex 的因为放在了一台欧洲的服务器上,在国内播放的时候总是会出现卡顿,一来是带宽限制,二来是经常发现有转码,所以常常需要我预先转码为低码率的视频才能流畅播放,出现的这个 SyncTV ,我可以搭配一台地理位置比较好的,比如日本的机器,然后通过代理的方式播放,不知道会不会提升一下使用体验。
  • 《被讨厌的勇气》读书笔记 怎么知道的这一本书
  • 修复 macOS 时区和时间错误 今天 macOS 上又发生了一个奇怪的问题,昨天晚上因为没有连接充电线,所以导致 MacBook 晚上自动关机了,看起来是因为没电自动关机了,但是早上看的时候还有一点点电,白天的时候没有任何操作就直接充电到满,但是晚一些使用的时候就发现系统的时间不太对了,在系统设置中强制同步系统时间,但没有用处,每一次同步都比当前的时间慢了一天和几个小时,甚至连分钟都对不上。于是就开始了一系列的修复过程。
  • 为播客爱好者制作的工具 Podwise Podwise 是一个针对播客的笔记软件,过去很长的一段时间里面都在寻找能够给播客记笔记的应用,之前在移动端发现了一个 [[Snipd]],可以在听到的时候,记录下播客中的精彩瞬间,还可以做笔记。但今天发现的这一款 Podwise 是基于网页的,可以在网页中播放,并且 Podwise 提供了语音转写的文字稿。