This page looks best with JavaScript enabled

Today I Learned/Thought/Found

 ·  ☕ 15 min read

记录每天所学到的想到的遇到的

linux 下的 logger 命令

在 debug 一些没有 stdout,stderr 的脚本的时候,可以用 logger 写日志,可以用 journalctl 查看日志。

1
2
3
4
5
6
7
SYNOPSIS
       logger [options] message

DESCRIPTION
       logger makes entries in the system log.

       When the optional message argument is present, it is written to the log. If it is not present, and the -f option is not given either, then standard input is logged.

$ echo eb3ae38f27191aa5f3850dc9cad00492b88b72404f9da135698679268041c54a | fold -w2 | tac | tr -d “\n”

1
2
3
$ echo eb3ae38f27191aa5f3850dc9cad00492b88b72404f9da135698679268041c54a \
  | fold -w2 | tac | tr -d "\n"
4ac541802679866935a19d4f40728bb89204d0cac90d85f3a51a19278fe33aeb

tac - concatenate and print files in reverse
fold - wrap each input line to fit in specified width

寻找一个能方便地完成 binary,hexadecimal, decimal 互相转换的办法?

我以前喜欢用 printf 来做 decimal 和 hexadecimal 之间的互相转换:

1
2
printf "%d\n" 0x1234 # 得到 4660
printf "%x\n" 123212 # 得到 1e14c

但是 printf 不能转换到 binary 格式。。。。。
所以用 python 吧,一行就能搞定:

1
2
3
4
5
6
$ python -c "print(bin(int('111', 16)))"
0b100010001
$ python -c "print(hex(int('111', 2)))"
0x7
$ python -c "print(hex(int('111', 8)))"
0x49

vim 的 –clean 参数

我想用 vim 阅读一个超级大的日志文件,可以使用 vim 的 –clean 参数,来避免加载那些自定义的 vim 插件。
https://vimhelp.org/starting.txt.html#--clean

如何触发 PCIe 设备的重新发现

1
2
root@Mufasa:/home/exec/my-flake/ > ls -ahl /sys/bus/pci/rescan
--w------- 1 root root 4.0K Jul 22 08:52 /sys/bus/pci/rescan

向这个文件写 1 ,就能触发 PCIe 设备的重新发现。

Ref:

  1. https://stackoverflow.com/questions/32334870/how-to-do-a-true-rescan-of-pcie-bus

waitpid(2)

wait for a child process to stop or terminate
https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html

linux command: waitpid

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
waitpid --help

Usage:
 waitpid [options] pid...

Options:
 -v, --verbose           be more verbose
 -t, --timeout=<timeout> wait at most timeout seconds
 -e, --exited            allow exited PIDs
 -c, --count=<count>     number of process exits to wait for

 -h, --help              display this help
 -V, --version           display version

For more details see waitpid(1).

发现一个好东西: fzf-git-checkout

https://polothy.github.io/post/2019-08-19-fzf-git-checkout/

Immutable vs Mutable Objects

https://medium.com/@katerinaCodes/immutable-vs-mutable-objects-d30ea96fb585

IN_NIX_SHELL 环境变量可以判断自己是否处于 nix-shell 当中

学习 NixOS

是的,我大概在一个星期之前的周末,安装了 NixOS。
我就只略微地了解了 NixOS 大致工作流程是怎样的,就直接上手安装了。
好在这个过程很顺利,然后我花了两天的时间去折腾 NixOS,学习它的配置方式,安装我日常需要的包,折腾 home-manager, 折腾 flake,nix-shell, overlay 等等,在两天的时间内,已经折腾到可以满足我日常使用需求的状态了。
关于 flake, nix-lang 的语法,配置文件的规则,overlay 等等我目前都没完全搞明白。
在这里贴一下我收集到的有帮助的链接:

  1. https://ianthehenry.com/posts/how-to-learn-nix/

tail 的 -F 控制参数

我正在用一个脚本做两件事情:1.删除当前项目目录下的 tmp 目录。2.在 tmp 目录下初始化并启动一个节点服务。
如果我用 tail -f ./tmp/data/logs/run.log 来查看日志的话,并不会继续查看删除 tmp 之后的新生成的 tmp 目录下的文件,而 tail -F 却允许我追踪重新创建的文件。

1
2
3
4
5
6
7

       -f, --follow[={name|descriptor}]
              output appended data as the file grows;

              an absent option argument means 'descriptor'

       -F     same as --follow=name --retry

调整 Cargo jobs 数量

以前我并没有调整 Cargo jobs 的数量,当我 执行 cargo build 的时候,我的 12 个 CPU 全部全力工作,这会导致我的操作系统略卡,不能及时响应我的键盘/鼠标动作。
所以我专门留一个 CPU 给操作系统,其他的 11 个 CPU 全力工作,这样我的操作系统就不会卡了。

参见: https://doc.rust-lang.org/cargo/reference/config.html#buildjobs

用 strace 追踪一个多线程进程的时候,可以考虑 -f 参数

也可以用 -p 仅仅指定一个线程 ID, LWP(Light Weight Process)

一个正在增长的文件,统计它的行数增长速度。

我正在观察节点同步过程中的日志,日志文件是一个不断增长的文件,我想知道它的增长速度(也就是区块增长的速度),于是想了一下,linux 有一个 叫 pvpipe viewer) 的命令能做的事情和我的需求很贴合,但是 pv 好像是用来统计 pipe 接收方的 byte 粒度的,而我要统计的是行数,man pv 看了下, pv 还有 -l 参数,完美的解决了我的需求:

1
tail -f data/logs/run.log | grep "block: " | pv -l > /dev/null

这样就能实时看到节点同步速度了。

ps -eLF 的结果里 LWP 代表 Thread Id?

我今天想用 ps 命令知道一个进程在运行过程中,都有哪些线程在跑,于是用了ps -eLF
发现了 NLWPLWP 列名, NLWP 是线程数, LWP 是线程 ID
LWP: Light Weight Process
https://www.thegeekstuff.com/2013/11/linux-process-and-threads/

Linux 下为给一个进程下面的所有线程都设置优先级

最近我正在为区块链节点的同步做 benchmark,同步过程中不仅有 IO 操作,也有 CPU 操作。我想看看同步耗时的瓶颈在于通过 p2p 拿到区块之后的 process_new_block() 动作,于是我就把节点的 p2p 相关部分给魔改注释掉,预先为 process_new_block() 准备好 headers 和 blocks,同时想着为节点进程设置最高优先级。
我一开始是这么做的:

1
sudo renice -n -20 -p [pid]

后来我用 htop 工具看了下,这个进程下有很多个线程,但是只有 PID 和 PGID 相同的那个线程的优先级被改了,其他的线程的优先级还是默认的。
于是我这样做:

1
sudo renice -n -20 -g [pid]

这样所有的线程的优先级都被改了成了最高优先级。
再看下 renice 命令的可用参数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
OPTIONS
       -n, --priority priority
           Specify the scheduling priority to be used for the process, process group, or user. Use of the option -n or --priority is
           optional, but when used it must be the first argument.

       -g, --pgrp
           Interpret the succeeding arguments as process group IDs.

       -p, --pid
           Interpret the succeeding arguments as process IDs (the default).

       -u, --user
           Interpret the succeeding arguments as usernames or UIDs.

原来 docker run 的 -p 参数是用 docker-proxy 来完成 ports mapping 的

https://github.com/moby/moby/blob/86ec93ccaf575eda78f82373de86b40d091c7d57/cmd/docker-proxy/main.go#L46-L58

使用 qbus 来控制 kde compositor 的 suspend/resume

还记得当初选择 KDE plasma 来作为我的 wm 是因为它有非常漂亮的特效,但是用久了就对那些特效没感觉了。于是我就关闭 compositor 了。
因为我偶尔需要让某些特殊窗口拥有 transparent 的效果,所以我就不得不控制 compositor 的启用、关闭。
搜了一下,我可以使用 qdbus 来做这件事情

1
2
3
$ qdbus org.kde.KWin /Compositor | grep method
method void org.kde.kwin.Compositing.resume()
method void org.kde.kwin.Compositing.suspend()
  • 恢复 compositor: qdbus org.kde.KWin /Compositor resume
  • 暂停 compositor: qdbus org.kde.KWin /Compositor suspend

Effective UserID, Real UserID, Saved UserID

- Real UserID:
The Real UserId is the UserID of its user who initiated the operation. It specifies which documents are accessible to this operation. It is the person who owns the operation.

- Effective UserID:
The Effective UserID is identical to the Real UserID, but it could be modified to permit a non-privileged person to use the documents that are typically accessible only to privileged users such as the root. It is used by the computing system to determine if you are allowed to do a particular task or not.

- Saved UserID:
The Saved UserID is a cast-off while a main task being performed contains high confidentiality. Most of the time, its root has to do work that requires less privilege. This can be accomplished by briefly transitioning to a non-privileged profile.

让 grep 保留 ps 第一行的列名

我平时这样用 ps 和 grep:

1
2
3
❯ ps -eF | grep -i 71435
exec       71435    6343  0 178062 4384   8 10:06 pts/21   00:00:00 vagrant ssh
exec       71443   71435  0  3866  6396   5 10:06 pts/21   00:00:01 /usr/bin/ssh [email protected] -p 2222 -o LogLevel=FATAL -o Compression=yes -o DSAAuthentication=yes -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /home/exec/Projects/github.com/eval-exec/ebpf-practice/.vagrant/machines/default/virtualbox/private_key

有时候我可能会改变 ps 的参数,同时我还想知道每一列都是什么意思,于是我想着怎么才能将 ps 输出结果的第一列保留下来。想了一下,我最后这样做:

1
2
3
4
5
function mygrep(){
        read -r headline < /dev/stdin
        echo ${headline}
        grep "$@"
}

看下效果:

1
2
3
4
❯ ps -eF | mygrep -i $(pidof vagrant)
UID          PID    PPID  C    SZ   RSS PSR STIME TTY          TIME CMD
exec       71435    6343  0 178062 4384   8 10:06 pts/21   00:00:00 vagrant ssh
exec       71443   71435  0  3866  6396   5 10:06 pts/21   00:00:01 /usr/bin/ssh [email protected] -p 2222 -o LogLevel=FATAL -o Compression=yes -o DSAAuthentication=yes -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /home/exec/Projects/github.com/eval-exec/ebpf-practice/.vagrant/machines/default/virtualbox/private_key

执行结果符合预期。

Linux coreutils 里的 rmdir 命令

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
man rmdir
NAME
       rmdir - remove empty directories

SYNOPSIS
       rmdir [OPTION]... DIRECTORY...

DESCRIPTION
       Remove the DIRECTORY(ies), if they are empty.

       --ignore-fail-on-non-empty
              ignore each failure that is solely because a directory is non-empty

       -p, --parents
              remove DIRECTORY and its ancestors; e.g., 'rmdir -p a/b/c' is similar to 'rmdir a/b/c a/b a'

其实也可以用 find

1
find . -type d -empty -delete

How to remove all empty directories in a subtree?

Jetbrians IdeaVIM 的 Forward 和 Back 不工作了

nmap <C-i>    :action Forward<CR>
nmap <C-o>    :action Back<CR>

https://youtrack.jetbrains.com/issue/VIM-2225

google chrome 无法播放视频

今天发现 YouTube 无法播放视频了,于是很纳闷?难道我这几天新安装了什么插件吗?仔细一回想,没有啊。
然后我从命令行启动 Chrome 发现以下日志:

1
2
3
4
5
❯ google-chrome-stable
[62820:62820:0513/165342.261311:ERROR:vaapi_wrapper.cc(1136)] vaQuerySurfaceAttributes failed, VA error: invalid parameter
[62820:62820:0513/165342.261383:ERROR:vaapi_wrapper.cc(1083)] FillProfileInfo_Locked failed for va_profile VAProfileH264Main and entrypoint VAEntrypointVLD
[62820:62820:0513/165342.261421:ERROR:vaapi_wrapper.cc(1136)] vaQuerySurfaceAttributes failed, VA error: invalid parameter
[62820:62820:0513/165342.261452:ERROR:vaapi_wrapper.cc(1083)] FillProfileInfo_Locked failed for va_profile VAProfileH264High and entrypoint VAEntrypointVLD

奇怪,看起来是音视频硬件加速出了问题。

vainfo 发现了诡异的地方:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
❯ vainfo
vainfo: VA-API version: 1.14 (libva 2.14.0)
vainfo: Driver version: Splitted-Desktop Systems VDPAU backend for VA-API - 0.7.4
vainfo: Supported profile and entrypoints
      VAProfileMPEG2Simple            : VAEntrypointVLD
      VAProfileMPEG2Main              : VAEntrypointVLD
      VAProfileMPEG4Simple            : VAEntrypointVLD
      VAProfileMPEG4AdvancedSimple    : VAEntrypointVLD
      <unknown profile>               : VAEntrypointVLD
      VAProfileH264Main               : VAEntrypointVLD
      VAProfileH264High               : VAEntrypointVLD
      VAProfileVC1Simple              : VAEntrypointVLD
      VAProfileVC1Main                : VAEntrypointVLD
      VAProfileVC1Advanced            : VAEntrypointVLD

有一行是 unknown profile

https://forum.manjaro.org/t/nvaapi-video-acceleration-on-google-chrome-stable-not-working/100109/3

从这个 issue 看到说需要安装 libva-vdpau-driver-chromium ?奇怪,以前我从来没安装过这个包啊。

1
2
  yay -S libva-vdpau-driver-chromium
  # note: Installing libva-vdpau-driver-chromium will remove: libva-vdpau-driver

安装 =libva-vdpau-driver-chromium= 完之后:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
 ❯ vainfo
  vainfo: VA-API version: 1.14 (libva 2.14.0)
  vainfo: Driver version: Splitted-Desktop Systems VDPAU backend for VA-API - 0.7.4
  vainfo: Supported profile and entrypoints
  VAProfileMPEG2Simple            : VAEntrypointVLD
  VAProfileMPEG2Main              : VAEntrypointVLD
  VAProfileMPEG4Simple            : VAEntrypointVLD
  VAProfileMPEG4AdvancedSimple    : VAEntrypointVLD
  VAProfileH264Main               : VAEntrypointVLD
  VAProfileH264High               : VAEntrypointVLD
  VAProfileVC1Simple              : VAEntrypointVLD
  VAProfileVC1Main                : VAEntrypointVLD
  VAProfileVC1Advanced            : VAEntrypointVLD

再次启动 chrome 又发现新的问题

[48720:48720:0513/172226.125496:ERROR:gl_utils.cc(319)] [.WebGL-0x3b600379bf00]GL Driver Message (OpenGL, Performance, GL_CLOSE_PATH_NV, High): GPU stall due to ReadPixels

奇怪?这次看起来是显卡的问题, GPU stall 了。

linux 的 faillock

今天感觉键盘上有很多灰尘,想擦一擦,于是先锁屏,然后用湿巾疯狂擦了几下键盘,擦完发现因不小心触碰了很多次解锁键,失败次数过多,得等 10 分钟后才能解锁。
于是了解到了: faillock

https://linux.die.net/man/8/faillock

只能以 root 身份从 tty 登录,然后

1
  faillock --user ${USER} --reset

vim 中的 ysiw, 和 cs

1
2
3
4
5
6

ci" - change inside double quotes

ci) - change inside curved brackets

ci} - change inside curly brackets

ysiw] surround a text object with ‘=’

https://github.com/tpope/vim-surround/issues/128

linux 下从进程的 pid 去寻找这个 pid 属于哪个 docker 容器

今天有同事发现公司一台服务器占用的资源较多,他从 =top= 拿到了 =pid= 。
于是搜了一下, =/proc/= 下面可以查看 =/proc/${pid}/cgroup= 来得到 =containerId=

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11

  ❯ docker run -d --rm --net="host" --name mymongo -e MONGO_INITDB_ROOT_USERNAME=root -e MONGO_INITDB_ROOT_PASSWORD=123456 mongo:5.0.0
  e7cd5c86843ddb2fe6e1b96e24702f193bf319ffc5f667f1728bff1f7fb18d6e
  ❯ ps aux | grep -i mongod
  999      1015717 21.3  0.1 1534516 105496 ?      Ssl  16:11   0:00 mongod --auth --bind_ip_all
  exec     1016018  0.0  0.0   9760  2436 pts/74   S+   16:11   0:00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn --exclude-dir=.idea --exclude-dir=.tox -i mongod
  ❯ cat /proc/$(pidof mongod)/cgroup
  0::/system.slice/docker-e7cd5c86843ddb2fe6e1b96e24702f193bf319ffc5f667f1728bff1f7fb18d6e.scope
  ❯ docker ps
  CONTAINER ID   IMAGE         COMMAND                  CREATED         STATUS         PORTS     NAMES
  e7cd5c86843d   mongo:5.0.0   "docker-entrypoint.s…"   2 minutes ago   Up 2 minutes             mymongo

今天学到了 xargs 的 –max-procs 参数

我负责公司以太坊节点的数据导出到 apache parquet的工作,我为erigon写的导出工具是单线程的,导出数据不仅会有磁盘的I/O操作,也会有一些消耗CPU的压缩操作。
以太坊节点所在的机器有16个核,我以前是这样写并发导出脚本的:(为了突出重点,我做了精简)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
MAX_PROCESS=14
parallelCount=0
for endBlock in $(seq 10000 -1000 1); do
  ${EXPORT_CLI} &>> export.log &
  if [ ${parallelCount} -eq ${MAX_PROCESS} ]; then
    wait
    parallelCount=0
  fi
done
wait

这段代码的缺点是:在 ${parallelCount} -eq ${MAX_PROCESS}true的时候,程序会一直等待,即使并发任务数量降为1。这不是我能够容忍的。
于是我了解到了 xargs--max-procs

-P max-procs, –max-procs=max-procs
Run up to max-procs processes at a time; the default is 1. If max-procs is 0, xargs will run as many processes as possible at a time. Use the -n option or the -L option with -P; otherwise chances are that only one exec will be done. While xargs is running, you can send its process a SIGUSR1 signal to increase the number of commands to run simultaneously, or a SIGUSR2 to decrease the number. You cannot increase it above an implementation-defined limit (which is shown with –show-limits). You cannot decrease it below 1. xargs never terminates its commands; when asked to decrease, it merely waits for more than one existing command to terminate before starting another.

于是我将代码这样修改:

1
2
3
4
5
6
7
function run_export_trace(){
  block=$1
  export_cli=$2
  ${export_cli} &>> export.log
}
export -f run_export_trace
seq 14340000 -${STEP} 1 | xargs -i --max-procs ${MAX_PROCESS} bash -c  "run_export_trace {} ${EXPORT_CLI}"

完美!这样cpu就不会闲着了。

我想将我的私人文件不被 git track, 但又不方便加入到 .gitignore 里面

我在和他人合作开发一个项目的时候,会自己写很多私有的脚本,每次在 git add 的时候都要关心一下有没有把不该track的东西给track了,本来可以加入到 .gitignore 里, 但是我又不想把我的私人文件加入到 .gitignore 里。
搜了一下, 也可以加入到 .git/info/exclude 里, 这个文件不会被 git track.
https://git-scm.com/docs/gitignore

Linux umount 时遇到: target is busy

今天坐在我工位对面的同事尝试对存放以太坊节点数据的磁盘执行 umount操作, 遇到了 target is busy这个问题。我的直觉告诉我这应该是有个进程正在读写这块硬盘。所以 umount 才会失败。
于是立即学习一下 core/psmisc 包里面的fuser 命令,和 lsof 命令。

man手册可以查到:

fuser: fuser displays the PIDs of processes using the specified files or file systems.

fuser returns a non-zero return code if none of the specified files is accessed or in case of a fatal error. If at least one access has been found, fuser returns zero.

fuserACCESS 列展示了相关进程的具体 access 信息

 c      current directory.
 e      executable being run.
 f      open file.  f is omitted in default display mode.
 F      open file for writing.  F is omitted in default display mode.
 r      root directory.
 m      mmap'ed file or shared library.
 .      Placeholder, omitted in default display mode.

fuser-m 选项:

-m NAME, –mount NAME
NAME specifies a file on a mounted file system or a block device that is mounted. All processes accessing files on that file system are listed. If a directory is specified, it is automatically changed to NAME/ to use any file system that might be mounted on that direc‐
tory.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
❯ fuser -m /run/media/exec/vax/ -v
                     USER        PID ACCESS COMMAND
/run/media/exec/vax: root     kernel mount /run/media/exec/vax
                     exec      269858 ..c.. zsh
                     exec      269933 f...m gitstatusd-linu
❯ fuser -m /run/media/exec/vax/ -v
                     USER        PID ACCESS COMMAND
/run/media/exec/vax: root     kernel mount /run/media/exec/vax
                     exec      269933 f...m gitstatusd-linu
❯ fuser -m /run/media/exec/vax/ -v
                     USER        PID ACCESS COMMAND
/run/media/exec/vax: root     kernel mount /run/media/exec/vax
                     exec      269933 f...m gitstatusd-linu
❯ fuser -m /run/media/exec/vax/ -v
                     USER        PID ACCESS COMMAND
/run/media/exec/vax: root     kernel mount /run/media/exec/vax

我注意到,即使我的zsh 离开了 外置硬盘所在的目录时, 这个硬盘依然被使用着,因为我用了 zsh 的一个 git status daemon 插件,这个插件估计会定时获取远程 git 仓库的状态。所以 fuser 展示了 gitstatusd-linux
后来我退出了 zsh shell, gitstatusd-linux 才退出。

https://unix.stackexchange.com/questions/3109/how-do-i-find-out-which-processes-are-preventing-unmounting-of-a-device

vim 使用 column 命令将若干列文本对齐

我的需求是这样的,想把这三列文本从上面的样子变成下面的样子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    private String transactionHash;
    private String blockHash;
    private Long blockNumber;
    private String fromAddress;
    private Long gas;
    private Long gasPrice;
    private String input;
    private Long nonce;
    private String toAddress;
    private Integer transactionIndex;
    private BigDecimal transactionValue;
    private Long blockTimestamp;
    private Receipt receipt;


private  String      transactionHash;
private  String      blockHash;
private  Long        blockNumber;
private  String      fromAddress;
private  Long        gas;
private  Long        gasPrice;
private  String      input;
private  Long        nonce;
private  String      toAddress;
private  Integer     transactionIndex;
private  BigDecimal  transactionValue;
private  Long        blockTimestamp;
private  Receipt     receipt;

只需进入 vimVISUAL 模式,选中那十几行,然后 :!column -t 即可。

将 Google NCR 设置为浏览器默认搜索引擎

我不喜欢 google 返回我和我位置信息相关的搜索结果,于是设置一下 Google NCR (No Current Region)
https://10wontips.blogspot.com/2018/07/always-search-google-in-english-by.html

我今天学到的 Linux 命令: disown

为了搞懂 disown 命令,必须得搞明白 linuxjobs 这个概念。
job 其实就是 shell 管理下的进程,每个 job 都有唯一的 job ID , job 有 3 中状态: foreground , background (在命令末尾用了 & 符号), stopped (按下 Ctrl-Z 会使得前台进程处于该状态)
job 相关的命令有这几个:

1
2
3
jobs # 列出 jobs 列表
bg %n # 让该 job 在后台工作
fg %n # 让该 job 在前台工作

如果你其他以 cmd & 的方式让一个进程工作在后台,当你退出 shell 后,该进程就会挂掉,要么你用 nohup 来启动,或者考虑 disown

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
$ help disown
disown: disown [-h] [-ar] [jobspec ... | pid ...]
    Remove jobs from current shell.

    Removes each JOBSPEC argument from the table of active jobs.  Without
    any JOBSPECs, the shell uses its notion of the current job.

    Options:
      -a        remove all jobs if JOBSPEC is not supplied
      -h        mark each JOBSPEC so that SIGHUP is not sent to the job if the
                shell receives a SIGHUP
      -r        remove only running jobs

    Exit Status:
    Returns success unless an invalid option or JOBSPEC is given.

disown 可以让指定 jobjob table 中移除,这样 即使你退出 shell, 后台进程也不会挂掉。
其中 -h 参数可以让 disown 在终端退出之后才生效。

可以做个实验:

  1. 从 shell 中以命令的形式启动 discord :/usr/bin/discord --balabala
  2. Ctrl-Z 暂停 discord
  3. ps -eF | grep discord # 查看 discord 进程 的父进程是谁,应该是 shell 进程
  4. 执行 disown # 从 job table 中移除 discord 这个 job
  5. kill -CONT [discord 的 PID]
  6. ps -eF | grep discord # 查看 discord 进程 的父进程是谁,应该不是 shell 进程了,在我本机上是 systemd 进程

vim 用户必须了解的 的 motion 和 operation

https://www.barbarianmeetscoding.com/boost-your-coding-fu-with-vscode-and-vim/editing-like-magic-with-vim-operators/

awk 不定长句子的最后一个单词

1
awk '{ print $(NF) }'

NF 表示这行句子的字段数。

vmtouch: 一个可以分析/控制文件系统缓存的工具

我拥有很多 roamXXXX.org 文件, 还有一个超级大的 org-journal文件,每当我第一次用emacs打开这些大文件后,感受到明显的卡顿,我认为这明显的卡顿其中从磁盘冷加载文件贡献了 30% 的卡顿,然后就是解析大文件,格式化和 highlight 贡献了 70% 的卡顿。于是我想让电脑在第一次开机的时候,将这些预读一下,旁加载到page cache里。最简单粗暴的方法,就是写个循环,把这些文件都 cat * > /dev/null, 后来找到了更为优雅的工具: vmtouch
https://hoytech.com/vmtouch/

1
2
3
vmtouch -vt ~/.emacs.d/
vmtouch -vt ~/org/roam/
vmtouch -vt ~/org/daily/

vmtouch 可以将文件 touch 进内存, 也可以将内存中的文件缓存 evict 出内存。

vmtouch 的用了这些系统调用:

1
2
3
4
5
#include <sys/mman.h>
int mincore(void *addr, size_t length, unsigned char *vec);

#include <fcntl.h>
int posix_fadvise(int fd, off_t offset, off_t len, int advice);

scrcpy 控制安卓手机

我拥有一个安卓手机,没有 root,今天想通过 Linux 系统来控制手机,于是折腾了一下,找到了 scrcpy 这个包:

1
2
3
❯ sudo pacman -Ss scrcpy
archlinuxcn/scrcpy 1.19-1 [installed]
    Display and control your Android device

https://github.com/Genymobile/scrcpy

注意是scrcpy不是scrapyscrapy是 python 的一个爬虫框架,我们需要的是scrcpy
我本来可以通过 usb 数据线链接手机,然后开启 adb 调试模式的,但是嫌麻烦。找到了通过 wifi 链接手机 adb 调试的方案:
并且通过 adb 解锁手机锁屏。
https://stackoverflow.com/questions/29072501/how-to-unlock-android-phone-through-adb
这样就能愉快的操控手机了~

Linux 控制外接显示器的亮度

因为我最近把外接显示器放置的比较远,我目前在坐的位置是面对窗户并且面朝东。早上阳光非常刺眼,就得将显示器亮度调高点才合适,晚上又得吧显示器亮度调暗。我懒得伸手去操作显示器,所以从终端控制:
我用的 archlinux,需要这个包

1
2
3
4
❯ sudo pacman -Sii ddcutil
Repository      : extra
Name            : ddcutil
Description     : Query and change Linux monitor settings using DDC/CI and USB.

然后 load i2c-dev module

1
modprobe i2c-dev

现在 ddcutil 就可以使用了:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  ~
❯ sudo ddcutil capabilities | grep "Feature: 10"
   Feature: 10 (Brightness)
  ~
❯ sudo ddcutil getvcp 10
VCP code 0x10 (Brightness                    ): current value =    50, max value =   100
  ~
❯ sudo ddcutil setvcp 100
Missing argument(s)
  ~
❯ sudo ddcutil setvcp 10100
  ~
❯ sudo ddcutil capabilities | grep "Feature: 10"
   Feature: 10 (Brightness)
  ~
❯ sudo ddcutil getvcp 10
VCP code 0x10 (Brightness                    ): current value =    50, max value =   100
  ~
❯ sudo ddcutil setvcp 10 100
  ~
❯ sudo ddcutil setvcp 10 20
  ~
❯ sudo ddcutil setvcp 10 100

大功告成,以后我再也不用伸胳膊去够显示器后面的调节按钮了。
:-D

Wikiwand: Wikipedia Modernized, 一个可以让你的 wikipedia 页面更好看的 chrome 插件

https://chrome.google.com/webstore/detail/wikiwand-wikipedia-modern/emffkefkbkpkgpdeeooapgaicgmcbolj

使用 kdeconnect-cli 为手机分享文件或文字

因为懒得去动鼠标/触摸板来 操作 kdeconnect 的图形界面,所以研究了一下如何在终端里将文件分享给手机。

1
2
3
4
5
kdeconnect-cli -l
kdeconnect-cli -a --id-only
kdeconnect-cli -d ${deviceid} --ping
kdeconnect-cli -d ${deviceid} --share ${realpath_of_file}
kdeconnect-cli -d ${deviceid} --share-text ${text} # 这会把文本分享给手机的粘贴板。

https://userbase.kde.org/KDE_Connect/Tutorials/Useful_commands

一个可以为远古时期的网页设置 syntax highlighting 的 firefox 插件:Enlight

https://addons.mozilla.org/en-US/firefox/addon/enlight/

zsh 快捷键相关的

其实很久以前就知道 bash/zsh 有很多移动鼠标的快捷键是从 emacs 那里移过来的。
今天我在 zsh 下工作时,巧合地触发了 M-x 键,它给我弹出了个 execute prompt, 于是我研究一番,zsh 下的 M-x 竟然和 emacs 的 M-x 相通,都是用来execute-command
https://unix.stackexchange.com/questions/440159/regarding-altx-in-zsh-and-how-to-bind-altx-to-something-else

ssh forward 遇到 bind: Cannot assign requested address

我今天在执行ssh -N -L port1:address:port2 server 时遇到了这个问题:
https://www.electricmonk.nl/log/2014/09/24/ssh-port-forwarding-bind-cannot-assign-requested-address/
原来是 ssh 试图 bind ipv6 地址
指定 ssh -4 使用 ipv4 地址 即可。

用命令行将 html 导出为图片

  1. google-chrome
1
google-chrome-stable --headless --disable-gpu --virtual-time-budget=10000 --window-size=3840,2160 --screenshot https://www.google.com

List of Chromium Command Line Switches

https://developers.google.com/web/updates/2017/04/headless-chrome
https://dschnurr.medium.com/using-headless-chrome-as-an-automated-screenshot-tool-4b07dffba79a

  1. wkhtmltoimage
1
wkhtmltoimage --width 1980 --height 1024  --quality 100 --javascript-delay 10000 https://www.google.com google.png

Emacs 将 org-journal-entry 同步到 telegram channel 里

我使用 org-journal 来记录生活,但是 org-journal 是离线的,我创建了个 bot 来将单条 org-journal-entry 同步到 channel里。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
(defun exec/get-org-entry-summary ()
  (interactive)
  (setq urlraw (format
    "https://api.telegram.org/bot%s/sendMessage?chat_id=@%s&text="
    (read-file "/home/vory/.emacs.d/config/tgsync.token")
    (read-file "/home/vory/.emacs.d/config/chatid.priv")
    ))
  (setq urlraw (concat urlraw   (buffer-substring (line-beginning-position) (line-end-position))))

  (message urlraw)
  (setq urlq (url-encode-url urlraw))

  (setq url-proxy-services
  '(("http" . "127.0.0.1:1081")
 ("https" . "127.0.0.1:1081")))
  (url-retrieve-synchronously urlq)
  (message "sync to telegram channel success"))

茴香豆的茴有几种写法之 VIM 有哪几种退出方式?

  • :wq / ZZ / :x
  • :q! / ZQ

日志里面第一列是 ip, 查询出现次数前 10 的 ip

1
cat xxx.log | awk '{ print $1 }' | sort -n | uniq -c | sort -r -k1 | head 10

grep pdf 文件

ripgrep-all

为 tmux 的 pane 名称设置不同的 emoji 后缀

生活要过的多姿多彩,同样的,我的终端也必须多姿多彩。于是我给 tmuxpanel添加了随机的emoji后缀
写一个shell脚本,放进我喜欢的emoji

1
2
3
EMOJIS=(😀 😃 😄 😁 😆 😅 🤣 😂 🙂 🙃 😉 😊 😇 🥰 😍 🤩 😘 )
SELECTED_EMOJI=${EMOJIS[$RANDOM % ${#EMOJIS[@]}]};
echo -n $SELECTED_EMOJI

然后在tmux里这样设置pane的名称,:

1
set-option -g automatic-rename-format '#{b:pane_current_path}[#(/home/vory/Dotfiles/tmux/pick.sh)]'

大功告成!

direvent

GNU direvent - Summary [Puszcza]

OCR 应用: tesseract

有时候身边的同事在排查问题的时候,会从用户那里得到图片形式的hash,为了debug,我本可以手工将图片形式的哈希转化为文本形式的,可是我实在是嫌麻烦,于是玩了下这个从 2006 年开始由Google maintain 的 OCR工具: tesseract-ocr/tesseract

ArchLinux 下所需的包

tesseract

1
> sudo pacman -S tesseract tesseract-data-chi_sim tesseract-data-chi_tra tesseract-data-eng

第一个是主程序,其他的都是由Google训练好的中文和英文模型库。
tesseract 的使用规则是这样的:

1
2
3
 tesseract FILE OUTPUTBASE [OPTIONS]... [CONFIGFILE]...
 # If FILE is stdin or - then the standard input is used.
 # If OUTPUTBASE is stdout or - then the standard output is used.

我的使用流程是: 从屏幕上截图,截图会自动保存到粘贴版,然后:

1
xclip -sel clip -target image/png -o | tesseract stdin stdout -l chi_sim -c preserve_interword_spaces=1

如果不加preserve_interword_spaces=1 的话,识别出的结果就会有烦人的空格。

结果很准确,甚至是同时有中文英文和符号的图片都能识别!

使用 sed 获取一个文件位于两个关键词之间的内容

比如:

> cat file.txt
first line :head
second line
third line
apple
forth line
...
tiger
last line
tail
1
2
3
4
5
> sed -n '/apple/,/tigger/p'  file.txt
apple
forth line
...
tiger

goland 缺失的功能

我用goland开发公司的项目,很喜欢golandrename usages of 变量/函数 A to 变量/函数 B的功能,但是我却不能对 import 这么做, 要是想改变整个项目都某一个包的引用,不得不使用 sed:

1
find . -name '*.go' -type f -exec sed -i 's/tg-service/tg-service\/bridge/g' {} ';'

*nix 环境,快速生成大量随机的 leetcode 测试用例

当我在 leetcode做了一道算法题后, 我会先在心里考虑一下输入的边界情况(或者非法输入),时间复杂度(要是数据里过大并且我的算法时间复杂度太差就会 Time Limit Exceed)。

所以我要么手动在 test cases 里手写测试用例, 要么用 linux 下这么几个有用的命令随机生成大量的测试用例:

1
2
3
4
5
seq  # print a sequence of numbers

shuf #  generate random permutations

paste #   merge lines of files

用这三个简单的工具, 一般就能生成我想要的测试数据了。
比如我想生成一个数组, 数组的每个元素都是数字,整个数组要是 unsorted:

要是想要超大的数据量, 我一般会写到 /tmp/ 里,再配合 xclip 将内容读进到 粘贴板, 最终粘贴到网页里去

https://leetcode.com/problems/combination-sum/solution/

1
2

seq 100 | shuf | paste -s -d ,

我喜欢用 printf 配合这些工具输出我想要的格式:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
> cat gen.sh
N=100
if [[ $# -eq 1 ]];then
    N=$1
fi
for n in $(seq $N) ;
do
    if [[ $(($RANDOM % 3 )) -eq 0 ]];then
        echo $n
    fi
done


> printf "[%s]\n" "$(./gen.sh 365 | paste -s -d , )"

[3,10,11,18,21,22,32,37,40,44,45,46,48,50,52,53,55,57,61,63,64,65,66,68,69,76,79,90,91,93,95,96,99,100]

> printf "[%s]\n" "$(./gen.sh 365 | paste -s -d , )" | xclip -sel clip
# 生成随机结果, 并且复制到粘贴板

心中的疑惑

  1. 在终端里快速生成大量随机数的最佳实践是什么?

gorm 链接 MySQL 处理 Error 1390 错误

我在公司负责的项目中使用了 gorm, 有一次 批量插入数据时遇到了 1390 :too many placeholders
所以我不得不减少数据量,为了解决问题将代码这样修改:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import(
    gmysql "github.com/go-sql-driver/mysql"
)
type Transactions []Transaction

func (ts Transactions) Insert() error {
 if len(ts) == 0 {
  return nil
 }

 err := db.Clauses(clause.OnConflict{
  DoNothing: true,
 }).Create(&ts).Error
 if err == nil {
  return nil
 }

 var mysqlErr *gmysql.MySQLError
 if errors.As(err, &mysqlErr) && mysqlErr.Number == 1390 {
  mid := len(ts) / 2
  if err := ts[:mid].Insert(); err != nil {
   return err
  }
  if err := ts[mid:].Insert(); err != nil {
   return err
  }
  return nil
 }
 return err
}

https://stackoverflow.com/questions/18100782/import-of-50k-records-in-mysql-gives-general-error-1390-prepared-statement-con

Share on

EXEC
WRITTEN BY
EXEC
Eval EXEC