基础知识 - 变量和函数

Linux 下的 Shell 有很多, sh, bash, csh, zsh 等, 这里主要记录一下 bash 和 zsh 的一些不同之处

Parameter Expansion

Use an alternate value

1
2
${var:+WORD}
${var+WORD}

如果 var 没有设置或为空,则这个变量展开为 Nothing (注意:不是空 empty, 是 nothing), 如果被设置了(不包括被设置成空),它展开为 + 后面的 WORD.

如果冒号被省略,则 var 即使被设置为空,它也展开为 + 后面的 WORD

Indirect

1
${!var}

如果 var 的值是 MESA_DEBUG, 那么这个形式展开后是变量 MESA_DEBUG 的值,例如 export MESA_DEBUG=1, var=MESA_DEBUG, 则最后的展开结果是 1

Quoted

1
${var@Q}

@Q 指变量展开后的值被单引号引起来,例如 export ABC=abc, echo "ABC=${ABC@Q}" 的结果是 ABC='abc'

反斜杠 backslash \

\ 在 shell 中是用来转义字符的,就是说 echo "\\\\" 显示的实际只有一个 \, 而且 while read var 时要注意加 -r 选项,读入原始字串

经典命令

exec

exec 命令有 2 个特点:

  • 直接覆盖当前进程,就是说进程 PID 不变,但执行的代码被更换了
  • 原来的 shell 环境被销毁,这样当前的代码结束后,也就不会返回原 shell(没得返回), 直接退出, 所以循环中慎用 exec
  • 可以把它想像成系统调用 execve()

下面是 linux kernel 安装 bzImage 的一段代码,其中就使用了 exec, 保证列出的 4 个安装脚本中,只执行第 1 个存在的,不会重复安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# User/arch may have a custom install script
for file in "${HOME}/bin/${INSTALLKERNEL}" \
"/sbin/${INSTALLKERNEL}" \
"${srctree}/arch/${SRCARCH}/install.sh" \
"${srctree}/arch/${SRCARCH}/boot/install.sh"
do
if [ ! -x "${file}" ]; then
continue
fi

# installkernel(8) says the parameters are like follows:
#
# installkernel version zImage System.map [directory]
exec "${file}" "${KERNELRELEASE}" "${KBUILD_IMAGE}" System.map "${INSTALL_PATH}"
done

timeout

timeout 命令用来给一个 COMMAND 设定一个 DURATION, 这在自动化中很有用,比如

1
for i in `fd --type x`; do timeout -k 0.1 10 ./$i; done

假如当前在 VulkanExamples 的 bin 目录下,上面的命令表示让每个 demo 执行 10s 后结束(timeout 给它发 TERM 信号), 如果发了 TERM 信号后,又经过 0.1s (-k 0.1),这个 demo 还未能退出,就再发 KILL 信号,强制结束它

tree

tree 像一个简单的文件浏览器,但它并不是 shell 内置的命令,apt install treepacman -S tree 都可以安装。有时一个目录中包含太多的文件,tree 的默认输出就不太好浏览,这时可以只打印目录,并限制搜索深度

1
tree -L 2 -d

crontab

crontab -e (添加定时任务), 不光可以添加周期性的定时任务,也可以添加开机时一次性任务

1
@reboot /home/luc/mystart.sh

crontab 是每用户的, 就是说当前用户设定的任务,只有当前用户的权限,所以如果有些情况下任务执行需要 root 权限,就需要切换到 root 用户后 crontab -e

文本处理 - awk, sed, grep(rg) 三剑客

Linux 下的文本处理三剑客: grep, sed, awk, 除了它们其实还有一些小巧的命令,如 tr, cut 也可以帮助我们快速处理和格式化文本。
下面以一个例子为例。

awk

1
awk 'program' inputfile1 inputfile2 ...

awk 的调用形式就是上面这样的,而其中的 program 由若干条 rules 组成,而一条 rule 由一个 pattern 和一个 action 组成

1
2
3
pattern { action }
pattern { action }
...

sed

sed 和 awk 一样,都是按行处理文本的。

  • sed -n '2 {s/^/#/; p; q}' file
    • sed 默认会将每一行都打印出来, -n 取消这一行为
    • sed 可以在操作的前面指定位置和范围, 如
      • 行号
      • 正则表达式 /^foo/
      • 两个正则表达式锁定范围 /^foo/, /bar$/
    • 如果 -n 后,完全都不打印了,但如果又想将处理后的行打印出来,使用 p 命令
    • q 命令的作用是立即退出,sed 的默认行为是对第2行处理完后,虽然后面的行都不需要处理,但 sed 仍然会继续将后面的每行往模式空间加载。

grep(rg)

在 Linux 内核源码目录下,搜索 drivers/gpu/drm 下所有的 DRIVER_NAME 定义,并排序后格式化输出

命令如下:

1
2
3
4
rg '#define DRIVER_NAME' drivers/gpu/drm --no-heading \
| tr -s '\t' | tr '\t' ' ' | tr -s ' ' \
| awk -F':' '{printf("%-52s%-40s\n",$1,$2)}' \
| sort -k4
  • rg (ripgrep) 比 grep 更快,更强大
  • tr 在不带任何选项时,默认执行替换,例子是中将 tab 替换成 空格, -s 表示 squeeze-repeats, 就是去掉重复的字符,例如多个空格只保留一个
  • awk 天生支持 C-Style printf

引号

当混合使用 awk 和 sed 时,比较便利地处理引号的方法是定义 awk 变量 -v Q="'"

  • awk 的 printf() 函数第一个参数必须使用双引号 printf("%s: %s%d%s\n", $1, Q, $2, Q)
    • awk 中的用户自定义变量和内置变量,使用时都不需要加 $, 如 NR, NF
  • awk 和 sed 的命令字串必须用引号括起来,当用 awk 生成 sed 命令时,将单引号定义为 awk 变量尤其方便,可读性也强

行范围 (Line range)

sed, awk 都支持行范围,如 sed -n '3,5p', awk 'NR >= 3 && NR <= 5',它们的效果是一样的,都是只打印给定文件的 3 到 5 行, 除了行号, sed, awk 还支持通过正则匹配来指定行位置

1
sed -n '/foo/,$p'
  • $ 表示最后一行
  • p 是 sed print 命令的缩写
1
awk '/foo/ {f=1} f'
  • awk 实现行范围的方式与 sed 稍有不同,它在满足匹配 foo 这个条件时,将布尔变量 f 设置为 1,相当于从这一行开始,开启 print 打印这个默认操作
  • awk 的一条 rule 里,可以省略 pattern, 或者省略 action, 但不能同时两个都省略;如果省略 pattern, 则对每个输入行都执行 action, 如果省略 action, 则对每个匹配行执行 print action。这个例子里面, awk 的 program 包括两条 rules
    • /foo/ {f=1} 这条 rule 什么都没有省略
    • f 这条 rule 省略了 action, 所以对每个输入行执行 print action

它们两个的效果也是一样的,都是从第一个匹配 foo 的行开始,一直打印到文件结束。

正则匹配 (Regex match)

awk 中一个 rule 中的 pattern 部分可以只是一条 / 括起来的正则表达式,默认这个正则表达式的匹配对象是 $0, 也就是整行, 如

1
awk '/foo/'

它实际上是

1
awk '$0~/foo/ {print $0}'

它意思是只要当前行里包含 foo 这个字串,就打印这一行。所以 awk 的正则 pattern, 准确来说是用来搜索

默认情况下是 $0~/foo/, 那么不默认情况下,可以指定哪个 field 去“匹配”, 如

1
awk '$1~/foo/ && $3!~/bar/ {print}'

它意思是当前这条记录,如果第1个字段包含 foo 第3个字段不包含 bar, 那么就打印整条记录

TeX/LaTeX

TeX 是高德纳(Donald Knuth)发明的编程式排版语言,而 LaTeX 是莱斯利·兰波特(Leslie Lamport)在 TeX 的基础上开发的 TeX 的扩展宏集。

生成 PDF 的工具

  • pandoc 标记语言转换领域的"瑞士军刀"
    • 将 Markdown 生成 PDF
  • TexLive 开发最为活跃的 TeX 发行版之一
    • TexLive 是跨平台的,但一般在 Linux 下安装,MacOS 下是 MacTeX, Windows 下是 MiKTeX.
  • eisvogel 简洁的 pandoc LaTex 模板
    • eisvogel 要求一个完整的 TexLive 的安装环境,但通常像 CentOS 这样的 Linux 发行版自带的 TexLive 并不完整。

How to Install texlive.iso

Quick Install

将 TexLive 的镜像下载并挂载后,通过顶层目录下的 install-tl 这个 Perl 脚本程序安装,整个安装过程要注意以下几点。

mount ISO image

假设在 Linux 下,通过 root 用户或 sudo 挂载镜像文件

1
2
mkdir -p /mnt/iso
mount /path/to/texlive.iso /mnt/iso -o loop

因为 ISO 文件系统是只读文件系统,所以如果想在 /mnt/iso 写入时,还需要借助 Linux 的 OverlayFS 进行再次挂载,之后在目录 /mnt/merged 里就有一份可写版的镜像了

1
2
mkdir -p /mnt/{upper,work,merged}
mount -t overlay overlay -o lowerdir=/mnt/iso,upperdir=/mnt/upper,workdir=/mnt/work /mnt/merged

run installer

TexLive 的 installer 是一个 perl script, 提供 text mode 和 GUI mode 两种安装模式.

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
======================> TeX Live installation procedure <=====================

======> Letters/digits in <angle brackets> indicate <=======
======> menu items for actions or customizations <=======
= help> https://tug.org/texlive/doc/install-tl.html <=======

Detected platform: GNU/Linux on x86_64

<B> set binary platforms: 1 out of 6

<S> set installation scheme: scheme-full

<C> set installation collections:
40 collections out of 41, disk space required: 7262 MB (free: 168365 MB)

<D> set directories:
TEXDIR (the main TeX directory):
!! default location: /usr/local/texlive/2022
!! is not writable or not allowed, please select a different one!
TEXMFLOCAL (directory for site-wide local files):
/usr/local/texlive/texmf-local
TEXMFSYSVAR (directory for variable and automatically generated data):
/usr/local/texlive/2022/texmf-var
TEXMFSYSCONFIG (directory for local config):
/usr/local/texlive/2022/texmf-config
TEXMFVAR (personal directory for variable and automatically generated data):
~/.texlive2022/texmf-var
TEXMFCONFIG (personal directory for local config):
~/.texlive2022/texmf-config
TEXMFHOME (directory for user-specific files):
~/texmf

<O> options:
[ ] use letter size instead of A4 by default
[X] allow execution of restricted list of programs via \write18
[X] create all format files
[X] install macro/font doc tree
[X] install macro/font source tree
[ ] create symlinks to standard directories
[X] after install, set CTAN as source for package updates

<V> set up for portable installation

Actions:
<I> start installation to hard disk
<P> save installation profile to 'texlive.profile' and exit
<Q> quit

Enter command:
  • D: 设置安装路径,相当于指定 --prefix
  • P: 保存安装的配置到文件 texlive.profile, 之后可以直接编辑这个文件,运行 install-tl 时通过 --profile 可以直接读取这个文件中的安装配置
1
2
3
4
5
6
7
8
9
10
11
12
13
Options customization:

<P> use letter size instead of A4 by default: [ ]
<E> execution of restricted list of programs: [X]
<F> create all format files: [X]
<D> install font/macro doc tree: [X]
<S> install font/macro source tree: [X]
<L> create symlinks in standard directories: [X]
binaries to: /usr/bin
manpages to: /usr/man
info to: /usr/info
<Y> after install, set CTAN as source for package updates:
[X]

最好勾选此选项,避免使用 TexLive 时各种 Not Found, 原因是 TexLive 默认安装路径并不是标准 Linux 可执行程序的路径(如 /usr/bin), 而是 /usr/local/texlive, 如在 x86_64 安装 texlive2022.iso, 则可执行程序被安装在 /usr/local/texlive/2022/bin/x86_64-linux. 假如不想因为该路径没有在 PATH 里,最好就是在安装时直接在 /usr/bin 下创建相应符号链接。

Non-interactive Installation

当你有一份 texlive.profile 时,就可以执行非交互式安装,install-tl 会直接按照 texlive.profile 文件里的配置安装,无需干预

1
./install-tl --no-interaction --profile=texlive.profile

texlive-full

在使用 xelatex, pdflatex 等 latex 程序时,可以常常遇到类似

! LaTeX Error: File 'fontawesome.sty' not found

xxx.sty 这样的报错,一般是缺少某个 texlive 包,但 texlive 的包太多了,如果懒得一个一个安装,可以

sudo apt install texlive-full

find 命令

find 命令用来在目录树里查找文件。本文主要介绍 GNU find. 它从每个 starting-point 开始递归搜索,通过求值 expression 的真值来确定输出结果。

find 的命令行组成

example-of-find

  • Options
  • Starting-point
  • Expression
    • Tests
    • Actions
    • Global options
    • Position options
    • Operators

Examples

  • 只在当前目录搜索(不递归)不以 f 或 g 或 h 开头的目录

    • find . -maxdepth 1 -name '[^fgh]*' -type d
      • -type d: 找目录
      • -type f: 找文件(不包括 symbolic link)
      • -type l: 找符号链接文件
  • 排除/proc 和 /tmp 这两个目录

    • find / -path /proc -prune -o -path /tmp -prune -o -name "README.md"
      • -prune 告诉 find 跳过前面的目录,也可以用 \( -o \) 将多个 -path 合并,只保留一个 -prune
  • 只在当前目录查找除了指定及隐藏目录以外的所有目录,打印并删除

    • find -maxdepth 1 \( -path ./gh -o -path ./aaa -o -path ./mesa-install -o -path ./1.3.290.0 -o -path ./1.3.280.1 \) -prune -o -type d ! -name ".*" -print -exec rm -rf {} \;
      • 注意匹配隐藏目录时用 .*, . 在 shell 里不是通配符
      • -print: 不让 ./gh, ./aaa 这些目录出现在 find 命令的输出结果中
  • 查找 ~/gh 目录下只有文件属主(u)有执行权限(x)的文件 (精确匹配文件的 permission bits)

    • find ~/gh -perm u=x -type f
  • 查找 ~/gh 目录下文件属主(u)有执行权限(x) 的文件(组用户(g)或其它用户(o)可能有或没有执行权限)

    • find ~/gh -perm -u=x -type f

Geometry Shader Input Layout Qualifiers

Geometry shader只能在接口限定符(interface qualifier)in前加Input Layout Qualifiers, 不能在输入块(input block), 块成员(block member), 或变量声明(variable declaration)前加Input Layout Qualifiers。

这些Input Layout Qualifiers有

Read more »

A language that doesn’t affect the way you think about programming, is not worth knowing.

Alan J. Perlis, Recipient of 1966 Turing Award

Read more »

最近在两个地方看到nightly这个词:

drm-tipdrm/drm-tip (我也不知道这两个仓库有什么区别,除了它们的Owner不同)

DRM current development and nightly trees

Read more »

简介

弈城围棋是弈城围棋网推出的一款围棋学习和网络对战的 App. 它可安装在包括 Windows, Android, iOS, iPad, MacOS 在内的各个平台。

Read more »

OpenGL Pipeline

OpenGL Pipeline Stage Flowchart

说明:

  1. 蓝色框表示是Programmable Shader Stages
  2. 虚线框表示是Optional Shader Stages

C++中的模板

C++中的模板可分为class template和function template. 它们之间存在不同,例如,function template不能partially specialized(偏特化)

Read more »
0%