Grub

Grub

/etc/sysconfig/grub

GRUB配置文件,实际上是/etc/default/grub的软连接

系统日志

/var/log

  • bootstrap.log:系统引导相关信息
  • cron:系统调度执行信息
  • dmesg:内核启动时信息,包括硬件、文件系统
  • maillog:邮件服务器信息
  • message:系统运行过程相关信息,包括IO、网络
  • secure:系统安全信息

Linux 远程工具

远程连接服务器

ssh

ssh:ssh登陆服务器

1
2
ssh <user_name>@<host> [-p <port>] [-i <private_key>]
[-F <config_file>]
  • 参数
    • -F:指定配置文件,简化命令,缺省~/.ssh/config
      • 有时会覆盖其余配置,可以指定-F /dev/null避免
    • -p:指定端口
    • -i:指定使用的私钥
    • -T:测试连接

ssh-keygen

ssh-keygen:生成ssh密钥

1
2
3
4
 # 生成位长为4096的RSA密钥
$ ssh-keygen -t rsa -b 4096 -C "xyy15926@163.com"
# 更改现有私钥密钥
$ ssh-keygen -p [-f keyfile] [-m format] [-N new_pwd] [-p old_pwd]
  • 参数

    • -t [dsa|ecdsa|ecdsa-sk|ed25519|ed25519-sk|ras]: 生成密钥类型
    • -f <output_keyfile>:密钥保存文件
    • -b <bits>:密钥位数
    • -C <comment>
    • -p:修改现有密钥密码
  • 在生成密钥时可以设置密钥,避免计算机访问权限被获取后密钥 被用于访问其他系统

    • 设置有密钥的私钥每次使用都需要输入密码
    • ssh-agent可以用于管理私钥密码,将私钥添加给 ssh-agent无需每次输入密码

ssh-add

ssh-add:管理ssh-agent代理密钥

1
2
 # 缺省将`$HOME/.ssh/id_rsa`私钥添加至`ssh-agent`
$ ssh-add <keyfile>
  • 参数
    • -l:查看代理中私钥
    • -L:查看代理中私钥对应公钥
    • -d <keyfile>:移除指定私钥
    • -D:移除所有私钥
    • -x/-X:锁定/解锁ssh-agent(需要设置密码)
    • -t <seconds>:密钥时限

ssh-agent

ssh-agent:控制和保存公钥验证所使用的私钥程序

  • 参数

    • -k:关闭当前ssh-agent进程
  • 启动方式

    1
    2
    3
    4
    5
    # 创建默认子shell,在子shell中运行`ssh-agent`
    # 会自动进入子shell中,退出子shell则`ssh-agent`关闭
    $ ssh-agent $SHELL
    # 启动后台`ssh-agent`进程,需手动关闭`ssh-agent`进程
    $ eval `ssh-agent`
  • 说明

    • ssh-agent添加私钥需要输入私钥密码 (无密码私钥无管理必要)
    • ssh-agent不会默认启动,应是每次需要大量使用私钥 前启动、添加私钥,然后关闭

/etc/init.d/sshd

sshd:ssh连接的服务器守护程序(进程)

1
2
3
4
$ sudo systemctl start sshd
# 使用`systemctl`启动
$ /etc/init.d/sshd restart
# 直接启动进程

scp

scp:secure cp,安全传输(cp)文件

  • 本机到远程

    1
    $ scp /path/to/file user_name@host:/path/to/dest
  • 远程到本机

    1
    $ scp user_name@host:/path/to/file /path/to/dest
    • 这个命令应该在本机上使用,不是ssh环境下
    • ssh环境下使用命令表示在远程主机上操作
    • 而本机host一般是未知的(不是localhost)
  • 远程到远程

rsync

实现本地主机、远程主机的文本双向同步

同步两种模式

同步过程由两部分模式组成

  • 决定哪些文件需要同步的检查模式

    • 默认情况下,rsync使用quick check算法快速检查 源文件、目标文件大小、mtime是否一致,不一致则 需要传输
    • 也可以通过指定选项改变检查模式
  • 文件同步时的同步模式:文件确定被同步后,在同步发生 之前需要做哪些额外工作

    • 是否删除目标主机上比源主机多的文件
    • 是否要先备份已经存在的目标文件
    • 是否追踪链接文件

工作方式

  • 本地文件系统同步:本质是管道通信

    1
    $ rsync [option..] src... [dest]
  • 本地主机使用远程shell和远程主机通信

    1
    2
    $ rsync [option...] [user@]host:src... [dest]
    $ rsync [option...] src... [user@]host:dest
    • 本质上是管道通信
  • 本地主机通过socket连接远程主机的rsync

    1
    2
    3
    4
    $ rsync [option...] rsync://[user@]host[:port]/src... dest
    $ rsync [option...] [user@]host::src... [dest]
    $ rsync [option...] src... rsync://[user@]host[:port]/dest
    $ rsync [option...] src... [user@]host::dest
    • 需要远主机运行rsync服务监听端口,等待客户端连接
  • 通过远程shell临时派生rsync daemon,仅用于临时读取daemon 配置文件,同步完成后守护进程结束

    • 语法同shell远程主机通信,指定--rsh/-e选项

参数说明

  • 可以有多个源文件路径,最后一个是目标文件路径
  • 如果只有一个路径参数,则类似于ls -l列出目录
  • 注意:如果原路径是目录
    • /结尾表示目录中文件,不包括目录本身
    • 不以/结尾包括目录本身

常用选项

同步模式选项
  • v/-vvvv:显示详细/更详细信息
  • p/--partial --progress:显示进度
  • -n/--dry-run:测传传输
  • -a/--archive:归档模式,递归传输并保持文件属性
  • -r/--recursive:递归至目录
  • -t/--times:保持mtime属性
    • 建议任何时候都使用,否则目标文件mtime设置为系统时间
  • -o/--owner:保持属主
  • -g/--group:保持group
  • -p/--perms:保持权限(不包括特殊权限)
  • -D/--device --specials:拷贝设备文件、特殊文件
  • -l/--links:如果目标是软链接文,拷贝链接而不是文件
  • z:传输时压缩

  • w/--whole-file:使用全量传输

    • 网络带宽高于磁盘带宽时,此选项更高效
  • R/--relative:使用相对路径,即在目标中创建源中指定 的相对路径

    1
    2
    3
    $ rsync -R -r /var/./log/anaconda /tmp
    # 将会在目标创建`/tmp/log/anaconda`
    # `.`是将绝对路径转换为相对路径,其后的路径才会创建
  • --delete:以源为主,对DEST进行同步,多删、少补

  • -b/--backup:对目标上已经存在文件做备份的
    • 备份文件名使用~做后缀
  • --backup-dir:指定备份文件保存路径,不指定为同一目录
  • --remove-source-file:删除源中已成功传输文件
连接
  • --port:连接daemon时端口号,默认873
  • --password-file:daemon模式时的密码文件
    • 可以从中读取密码文件实现非交互式
    • 是rsync模块认证密码,不是shell认证密码
  • -e:指定所需要的远程shell程序,默认ssh
    1
    $ rsync -e "ssh -p 22 -o StrictHostKeyChecking=no" /etc/fstab
  • --rsh:使用rsync deamon进行同步
检查模式选项
  • --size-only:只检查文件大小,忽略mtime
  • -u/--update:进源mtime比已存在文件mtime新才拷贝
  • -d/--dirs:以不递归方式拷贝目录本身(不目录中内容)
  • --max-size:传输最大文件大小,可以使用单位后缀
  • --min-size:传输的最小文件大小
  • --exclude:指定派出规则排除不需要传输的文件
  • --existing:只更新目标端已存在文件,不存在不传输
  • --ignore-existing:只更新在目标段不存在文件

SSH

/etc/ssh/sshd_config

全局系统ssh配置

1
2
3
4
5
6
7
8
RSAAuthentication
# 去掉注释启用RSA认证
PubkeyAuthentication yes
# 启用公私钥配对认证方式
AuthorizedKeyFile .ssh/authorized_keys
# 设置被认证的公钥存放文件
# 默认为`~/.ssh/authorized_keys`中
# 将其他主机公钥写入其中,即可从其使用密钥认证免密访问

~/.ssh

authorized_keys

/etc/.ssh/sshd_config中默认的存储其他主机公钥的文件,

  • 使用在其中的公钥可以使用公钥登陆,无需密码
  • 必须设置只有root用户有更改权限有效,否则报错
1
---pubkey---
id_rsa.pub

生成公钥

config

ssh访问远程主机配置

  • 每条配置对应一个ssh连接,配置后可以使用link_name直接 连接
1
2
3
4
5
6
7
Host <link_name>
HostName <host>
User <user_name>
Port <port>
IdentityFile <private_key>
IdentitiesOnly yes
PreferredAuthentications publickey
  • 默认私钥文件为:~/.ssh/id_rsa,可以指定特定私钥
  • 此文件中配置是ssh协议参数封装,适合任何可以使用ssh协议 场合:sshgitscp

Nginx 使用、配置

配置

  • 配置文件夹为/etc/nginx

基本配置

nginx.conf

nginx.conf:Nginx主配置文件,包含“全部配置”

  • 默认include

    • modules-enabled/*.conf:已启用模块
    • mime.types:代理文件类型
    • conf.d/*.conf:服务器设置
    • sites-enabled/*:已启用站点
  • user表示启动nginx进程的用户

    • 键值默认为www-data
    • 可修改为其他用户,使nginx具有访问某些文件的权限
    • 若是在nginx启动之后修改,需修改/var/log/nginx中 log文件的属主,否则无法正常log

http服务器设置

1
2
3
4
5
6
7
8
9
10
server{
listen 8080;
server_name localhost;
location / {
root /home/xyy15926/Code;
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
}
}
  • root:需要nginx进程可访问,否则403 Forbidden
  • autoindex:自动为文件生成目录
    • 若目录设置index index.XXX,不设置autoindex访问 目录则会403 Forbidden

https服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
server{
listen 443 ssl;
server_name localhost;
ssl_certificate /home/xyy15926/Code/home_config/nginx/localhost.crt;
ssl_certificate_key /home/xyy15926/Code/home_config/nginx/localhost.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
location / {
root /home/xyy15926/Code/statics;
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
}
}
  • ssl_certificatessl_certificate_key:SSL证书、私钥

    1
    2
    3
    4
    5
    6
    # 个人签发https证书,个人一般不会是受信任机构,所以还需要
    # 将证书添加进受信任机构(但是windows下有些有问题)
    openssl req -x509 -out localhost.crt -keyout localhost.key \
    -newkey rsa:2048 -nodes -sha256 \
    -subj '/CN=localhost' -extensions EXT -config <( \
    printf "[dn]\nCN=localhost\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:localhost\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth")

运行

1
2
3
 # Nginx启动、重启动
$ /etc/init.d/nginx start
$ /etc/init.d/nginx restart

Pandoc介绍

Pandoc

Pandoc:将文本在不同标记语言之间相互转换的工具

  • Pandoc使用Haskell开发,最新版本Pandoc可以使用Haskell平台 包管理器cabal安装

    1
    2
    3
    $ sudo apt install haskell-platform
    $ cabal update
    $ cabal install pandoc
  • Pandoc支持的标记语言格式包括 (具体可通过--list-input-formats查看)

    • Markdown
    • ReStructuredText
    • HTML
    • LaTeX
    • ePub
    • MS Word Docx
    • PDF
  • Pandoc输入、输出文本

    • 可从输入、输出的文件扩展名推测输入、输出格式
    • 缺省输入格式为Markdown、缺省输出格式为html
    • 若未指明输入、输出文件,则读取、写入标准输入、输出
    • 文本默认为utf-8编码,否则可以用iconv转换文本 编码进行输入、输出

Pandoc相关选项

基础选项

  • -f/-t:输入、输出格式
  • -o:输出文件
  • --number-sections/-N:为标题添加编号
  • --verbose:详细调试信息
    • 其中会给出资源文件目录~/.pandoc,存放模板等
  • --log:日志信息
  • --file-scope:分别转换每个文件
    • 指定多个输入文件时默认将多个文件拼接,空行分隔

信息选项

  • --list-input-formats/--list-output-formats:输入、 输出格式
  • --list-extensions[=FORMAT]:列出Markdown扩展支持情况
    • <FORMAT>-<EXT>可以增减格式中一个、多个扩展选项
  • --list-highlight-languages:语法高亮支持语言
  • --list-highlight-styles:语法高亮支持样式

模板选项

  • -standalone/-s:生成完整文件 (仅对可生成片段的某些格式:html、LaTeX)
    • 默认生成文档片段
    • 采用相应内值模板生成完整文件
  • --print-default-template=<FORMAT>/-D <FORMAT>:输出 对应格式的默认模板
  • --template=<TPL>:指定创建文档所需模板
  • --css=<URL>/-c <URL>:指定CSS样式表

自定义值传递

  • --variable=<KEY[:<VAL>]>/-V <KEY[:<VAL>]>:指定模板 变量取值
  • --metadata=<KEY[:<VAL>]>/-M <KEY[:<VAL>]>:指定 元数据字段取值
    • 元数据字段影响模板变量取值,同时影响底层文档元数据
  • --metadata-file=<FILE>:从YAML格式文件中设置元数据字段 取值

PDF生成相关

  • --toc:生成目录
  • --template=<TPL>:编译使用的LaTeX模板,缺省为自带
  • --latex-engine=<ENG>:指定LaTeX引擎,需安装
    • 默认pdflatex对中文支持缺失,建议使用xelatex
  • --highlight-style=<STY>:代码块语法高亮
    • 自带高亮样式可通过--list-highlight-styles查看
    • 也可指定高亮样式文件
  • --listings:LeTeX文档中使用Listings包格式化代码块
  • --biblatex/--natbib:指定处理参考文献程序
  • --bibliography=<FILE>:设置文档元数据中参考文献信息
  • -f markdown-implicit_figures设置Markdown格式,指定 图像保持原始位置,避免pdf中错位

HTML生成相关

  • --self-contained:将css、图片等所有外部文件压缩进html 文件中
  • Markdown中使用html标记可以在转换为html后保留,可以据此 设置转换后的样式

DOCX生成相关

  • --reference-doc=<FILE>:指定格式参考文件
    • 参考文件内容被忽略,就样式、文档属性被使用
  • --print-default-data-file=reference.docx:输出系统默认 模板
  • --extract-media=<DIR>:提取文档中多媒体文件至文件夹, 并在目标文件中设置对其引用

EPUB生成相关

  • --epub-cover-image=<FILE>
  • --epub-metadata=<FILE>
  • --epub-embed-font=<FILE>

数学公式渲染

  • --mathjax[=<URL>]
  • --mathml
  • --katex[=<URL>]

Pandoc模板

模板变量

模板变量:Pandoc模板中可以包含变量用于自定义模板

1
2
3
4
5
6
7
8
9
10
11
$title$						# 变量表示方法

$if(var)$ # 变量条件语句
X
$else$
Y
$endif$

$for(var)$ # 变量循环语句
X
$endfor$
  • 变量赋值方式
    • 命令行参数提供
    • 文档元数据中查找

Todo.txt

Todo.txt格式

  • todo.txt格式使用纯文本存储、表示任务
  • 存储任务的文本文件中每行表示一项task
  • todo.txt类清单管理应用因此一般具备如下特点
    • 待完成任务、已完成任务分为两个文件分别存储
    • 可以自由修改任务存储文件以修改任务内容

基本要素

todotxt_format_description

  • 任务结构:各部分之间使用空格分隔

    • x:任务完成标识符
    • 优先级:([A-Z])
    • 完成日期、创建日期:Y-m-d格式
    • 任务描述:任务主体部分
  • 任务描述部分可以包含各种类型的tag,tag格式上可以放在任务 任何部分,但习惯上放在末尾

    • project+标识
    • context@标识
    • [key]:[value]:metadata键值对,key表示键值对含义 (中间一般不用空格分隔,便于处理)
  • 常用特殊metadata键值对
    • 时间戳:t:Y-m-d
    • 截至日期:due:Y-m-d

Todo.txt工具

todo.txt-cli

todo.txt-cli:基于shell脚本管理todo.txt文件

  • 只提供基本todo.txt功能,可以通过自行添加脚本插件方式扩展

    • 插件文件即普通可执行脚本文件,todo.sh会将命令参数 传递给相应脚本文件
    • todo.sh [action]将直接调用相应action名称脚本 (可建立同名文件夹、文件管理,同名文件夹文件被调用)
  • 使用两个文件分别存储待完成任务、已完成任务

    • 待完成任务文件中可以自行x标记完成,然后使用命令 归档至已完成任务文件中

topydo

topydo:基本python脚本管理todo.txt文件

  • 提供了cli、prompt、column三种模式
  • 原生支持以下标签
    • due、start日期
    • 管理任务之间依赖管理
    • 重复任务

Vim 配置

打印信息

  • :echo:打印信息,但是信息不会保存
  • :echom:打印信息会保存在:messages
  • :messages:查看:echom保存的信息

设置选项

  • 设置选项方式

    • 命令行一次设置多个选项::set number numberwidth=6
    • 本地缓冲区设置::setlocal nonumber
  • 设置 bool 选项

    • :set <name>:打开选项
    • :set no<name>:关闭选项
    • :set <name>!:切换选项
    • :set <name>?:查看选项值(返回或no
  • 设置键值选项

    • :set <name>=value:设置选项值
    • :set <name>?:查看选项值
    • 键值选项支持运算:+=

statusline 状态栏设置

  • 状态栏代码通用格式:%-0{minwid}.{maxwid}{item}

    • -:左对齐
    • 0:使用”0”填充
    • %=:切换到状态栏右侧

    • %f:文件名

    • %F:完整路径文件名
    • %y:文件类型([text],[python])
    • %Y:文件类型(TEXT,PYTHON)

    • %l:当前行号

    • %L:总行数
    • %v/%V:列号
    • %c:字符列号
    • %p:文件位置百分比

    • %n:buffer number

    • %{&ff}:文件格式(DOS、UNIX)
    • %b:当前字符ACSII码
    • %B:当前字符16进制值
    • %m:modified flag([+],[-]表示不可修改)
  • 设置状态栏显式格式,既可以一行完成配置,也可以分开配置

    1
    2
    3
    4
    5
    6
    set statusline=%f\ -\ filetype:\ %y
    set statusline=%f
    set statusline+=%=
    set statusline+=%l
    set statusline+=/
    set statusline+=%L
    • 中间空格需要用“\“转义,“%%”转义“%”
  • laststatus:设置状态栏显示模式

    • 1:默认值,两个以上窗口才显示
    • 2:一直显示

折叠设置

  • foldmethod
    • manual:手动折叠选中的行(默认 zf 触发)
    • marker{{{` 到 `}}} 标记待折叠行(默认 za 触发)
    • indent:折叠缩进
    • syntax:语法折叠
  • foldlevel=<num>:设置 indent 折叠起始水平(zm 触发),即从 <num> 水平开始尝试折叠
  • foldlevelstart=<num>:设置文件打开时默认折叠水平
    • -1:初始不折叠
  • foldcolumn=<num>:用 <num> 行表示可可折叠状态

一些常用关键字

  • iskeyword=@,_,48-57,192_255:指定关键字

    • 下划线
    • ASCII 码位在 48-57 之间的字符(0-9)、192-255之间的字符
  • conceallevel=0:隐藏等级

    • 1
    • 2

键盘映射

1
:<mode>map <mark> {lhs} {rhs}
  • 注意:映射后不能跟注释,vim会认为整行都是命令

映射工作模式

  • 映射的工作模式可区分 6 种
    • normal 模式:输入命令时
    • visual 模式:可视区域高亮并输入命令时
    • select 模式:类似可视模式,但键入的字符对选择区替换
    • operator-pending 模式:操作符等待中
    • insert 模式:包括替换模式
    • command-line 模式:输入 :/ 命令时

映射命令设置

  • 映射命令设置的模式如下,对应都有如下非递归、取消命令

    • <mode>noremap[!]:非递归映射,即不会在其他映射中再次被展开
    • <mode>unmap[!]:取消映射
    • <mode>mapclear[!]

    |命令|模式| |——-|——-| |:map|normalvisualselectoperator-pending| |:nmap|normal| |:vmap|visualselect| |:smap|selection| |:xmap|visual| |:omap|operator-pending| |:map!|insertcommand-line| |:imap|insert| |:lmap|insertcommand-lineLang-Arg| |:cmap|command-line| |:tmap|终端作业|

特殊参数

  • 映射特殊参数

    • <buffer>:映射将局限于当前缓冲区
      • 优先级比全局映射高
      • 清除映射时同样需要添加参数
      • 可使用 <leader> 替代 <localleader> 可工作,但是不推荐
    • <nowait>:存在较短映射时,失效以其作为前缀的较长映射
    • <silent>:映射不在命令行上回显
    • <special>:特殊键可以使用<>记法
    • <script>:映射只使用通过以<SID>开头来定义的脚本局部映射来重映射优右值中的字符
    • <unique>:若存在相同命令、缩写则定义失败
      • 定义局部映射时,同样会检查全局映射
    • <expr>:映射的右值将被作为表达式被计算
  • 特殊参数说明

    • 特殊参数的尖括号<>是本身具有的,必须紧跟命令后面
    • 有些特殊参数在取消映射时同样需注明

omap

  • 应用方法:operator (操作) + operator-pending (移动、范围选择)
  • 预定义的 operator-pending 映射如 wawi(t,

    |按键 |操作 |移动 | |———-|———————-|———————-| |dw |删除(delete) |到下一个单词 | |ci( |修改(change) |在括号内 | |yt, |复制 |到逗号前 |

  • 自定义的 operator-pending 映射则需要

    • 选取一定范围:可同时指定开头、结尾(一般通过进入 visual 模式下选择范围)

      1
      2
      3
      4
      5
      6
      7
      " 下个括号内内容
      onoremap in( :<c-u>normal! f(vi(<cr>
      " 当前括号内容
      onoremap il( :<c-u>normal! f)vi(<cr>`
      " 选取使用 `===` 标记 markdown 标题
      onoremap ih :<c-u>execute "normal! ?^==\\+$\r:nohlsearch\rkvg_"<cr>
      onoremap ah :<c-u>execute "normal! ?^==\\+$\r:nohlsearch\rg_vk0"<cr>
    • 指定光标位置:光标当前位置为开头、指定位置为结尾

      1
      2
      " 移动至 `return` 前一行
      onoremap b /return<cr>

leaderslocalleader

leaderlocalleader:作为“前缀”的不常用的按键,后接其他字符作为整体映射

  • 用途

    • 避免覆盖太多按键原始功能
    • 约定俗成的规范,容易理解
    • 方便更改 <leader><localleader> 作为前缀设置
      • <leader>:对全局映射而设置的映射的前缀
      • <localleader>:只对某类(个)文件而设置的映射的前缀
    • <leader><localleader> 除了设置不同以外,没有太大区别,应用场合时约定规范,不是强制性的
  • <leader><localleader> 设置

    1
    2
    3
    4
    :let mapleader = "-"
    :nnoremap <leader>d dd
    :let maplocalleader = "\\"
    :nnoremap <buffer> <localleader>c I#<esc>
    • vim 会对 mapleadermaplocalleader 进行特殊的处理,不是简单的声明

Abbreviations 缩写

  • iabbrev:紧跟缩写输入非关键字后,缩写会替换为相应的完整字符串
    • 相较于映射
      • iabbrev 用于 insertreplacecommand-line 模式
      • iabbrev 会注意缩写前后的字符,只在需要的时候替换
    • iabbrev 同样支持特殊参数
      • <buffer>:仅限本地缓冲区
1
2
3
4
5
6
7
8
" 纠错
iabbrev waht what
" 简化输入
iabbrev @@ xyy15926@gmail.com
" 替换 `----` 为前个单词
iabbrev <buffer> ---- &mdash
" 替换 `return` 为 null
iabbrev <buffer> return nopenopenope
  • :set iskeyword? 即可查看关键字字符

Autocmd 自动命令

autocmd 使用

  • autocmd 注意事项

    • 同时监听多个事件,使用 , 分隔,中间不能有空格
    • 一般同时监听 bufnewfilebufread,这样打开文件时无论文件是否存在都会执行命令
    • 所有事件后面都需要注明适用场景,可用*表示全部场景,中间也不能有空格
    • autocmd 是定义命令,不是执行命令
      • 每次执行都会定义命令,而vim 不会忽略重复定义
      • 如::autocmd bufwrite * :sleep 200m,每次执行时都会重复定义命令
  • 缓冲区事件

    1
    2
    3
    4
    autocmd bufnewfile * :write
    autocmd bufnewfile *.txt :write
    autocmd bufwritepre *.html :normal gg=g
    autocdm bufnewfile,bufread *.html setlocal nowrap
  • filetype 事件(vim 设置缓冲区 filetype 时触发)

    1
    2
    3
    4
    autocmd filetype javascript nnoremap <buffer> <localleader>c i//<esc>
    autocmd filetype python nnoremap <buffer> <localleader>c i#<esc>
    autocmd filetype javascript :iabbrev <buffer> iff if ()<left>
    autocmd filetype python :iabbrev <buffer> iff if:<left>

augroup 自动命令组

  • 自动命令组

    1
    2
    3
    4
    augroup cmdgroup
    autocmd bufwrite * :echom "foo"
    autocmd bufwrite * :echom "bar"
    augroup end
  • 注意事项

    • 类似 autocmdvim 不会忽略重复定义,但是可以通过 :autocmd! 清除一个组

      :augroup cmdgroup : autocmd! : autocmd bufwrite :echom “foo” : autocmd bufwrite :echom “bar” :augroup end

Vim安装

安装选项

1
2
3
4
5
6
7
8
$ ./configure --with-features=huge\
--enable-multibyte \
--enable-python3interp \
--with-python3-config-dir=/usr/lib64/python3.4/config-3.4m/ \
--enable-pythoninterp \
--with-python-config-dir=/usr/lib64/python2.7/config/ \
--prefix=/usr/local
--enable-cscope
  • 按照以上命令配置,编译出的Vim版本中是动态支持 +python/dyn+python3/dyn

  • 此时Vim看似有python支持,但是在Vim内部 :echo has("python"):echo has("python3")都返回0

  • 之后无意中尝试去掉对python的支持,编译出来的Vim就是 可用的python3,不直到为啥

Vim KeyMapper CMD

Vim模式

Normal模式

Insert模式

Visual模式

Quickfix模式

quickfix模式主要思想时保存一个位置列表,然后提供一系列命令, 实现在这个位置列表中的跳转

  • 位置列表来源

    • 编译器输出信息
    • grep命令输出信息(cscope命令)
    • :vimgrep命令
  • quickfix中常用的命令有

    • :copen/:cw:打开quickfix模式窗口
    • :cclose:关闭quickfix窗口
    • :cc:显示详细错误信息
    • :cp:跳至下一个错误
    • :cn:跳至上一个错误
    • :cl:列出所有错误
    • :cw:如果有错误列表,则打开quickfix窗口
    • :colder/col:到前一个旧错误列表
    • :cnewer/cnew:到后一个新错误列表

Ex模式

底层编辑模型,normal下Q进入

Paste模式

Motion快捷键

normal模式下移动,visual模式下选取,无特殊说明visual和normal 模式通用

固定移动

基本

  • hjkl:左、上、下、右
  • gj/gk:虚上、虚下(光标移动排版意义上行) (可以尝试noremap交换和j/k的逻辑方便使用)
  • M:窗口中间行首各非空白字符
  • H/L:窗口顶/底scrolloff处行首各非空白字符
  • <c-i>/<c-o>:跳至下一个/上一个编辑处 (可以跨文件)

行内

  • w:下个单词开头
  • aw:整个单词
  • b/e:当前单词首/尾
  • W/B:下/上个非空格开头
  • E: 下个非空格结尾
  • g_:行尾,visual模式下不包括换行符
  • $:行尾,visual模式下包括换行符
  • 0:行首
  • ^:非空白字符行首
  • |:当前行第一列
  • <int>|:当前行第n列(不是字符)

全文

  • gg:文件首
  • G:文件尾
  • <int>G:第<int>
  • '<:之前visual模式选取起始行(一直保存直至下次选取)
  • '>:之前visual模式选取结束行
  • {/}:下/上一个空行
  • .:当前行
  • %:全文选取???

组合

这些快捷键的效果取决于当前状态

行内

  • f/F:向前/后移动到某字符(;,同向、反向重复)
  • t/T:till,向前/后移动到某字符前
  • i:在某个区域((), [], {}, w等)内(显然不能单独用 于normal)

全文

  • //?:命令行向前、向后查找(nN同向、反向重复)
  • */#:向前、向后查找当前单词
  • g*/g#:向前、向后查找当前字符串,包括非单独单词

Operation快捷键

区域进行操作可以和motion连用

内容修改

插入

  • i:insert进入insert模式
  • I(normal):行首insert进入insert模式
  • I(visual block):选中区域同时插入
  • a:add进入insert模式
  • A:行尾add进入insert模式
  • <c-e>:insert模式下复制下行当前位置字符至当前行

删除

  • d:删除选取区域
  • c:删除(修改)选中区域,进入insert模式
  • x/X:删除当前/前一个字符
  • s:删除字符,进入insert模式
  • dd:删除当前行
  • D:normal模式删除当前位置至行尾
  • <c-h>/<m-h>:insert模式backspace

复制、粘贴

  • ["<reg>]y:复制选中区域至寄存器<reg>,默认 "<reg>
  • yy:复制当前行
  • ["<reg>]p:粘贴"<reg>寄存器中内容,默认"<reg>

其他

  • J:合并下一行,<space>分隔
  • u/U(visual):转换为小、大写
  • ~(normal):当前字符大、小写切换(光标移动至下个字符)
  • ~(visual):选中区域大、小写切换
  • gu/gU(normal)区域转换为小、大写
  • g~区域大、小写切换
  • [num]>/<:右/左移动区域num个shiftwidth单位
  • =区域格式化(修改为标准缩进)
  • <c-d>/<c-i>:insert模式减少/增加缩进
  • gc(visual/normal):选中区域按行注释/取消注释 (应该是按vim的filetype确定注释格式)
  • <c-a>/<c-x>:将光标下数字增加/减少1,支持多种进制

功能性

记录

  • q<reg>:宏记录,记录行为于寄存器<reg>中,按下q则 停止记录
  • @<reg>:调用寄存器<reg>中的宏操作(不一定是q<reg> 记录的结果)
  • m<char>:记录当前位置于<char>中(不是寄存器中未知)
  • `\:回到<char>中记录的位置

撤销、redo

  • .:重复上一个操作
  • u:撤销上一个操作
  • <c-r>:继续执行,撤销u
  • <c-m>:等同于<cr>

外部功能

  • K:对当前单词调用keywordprg设置的外部程序,默认“man”

Diff

  • ]c/[c:比较窗口中移至下个不同的为止
  • do/dp:将当前比较窗口中不同区域,同步为/至另一个 窗口该位置

其他

  • q::vim命令历史窗口

界面变动

窗口

Window

  • <c-w-h/j/k/l>:切换至左/下/上/右窗口
  • <c-w-w>:轮换窗口(切换活动窗口)
  • <c-w-t/b/p>:切换至最左上/右下/前个窗口
  • <c-w-+/->:竖直方向扩展/收缩当前窗口
  • <c-w->/<>:水平方向扩展/收缩当前窗口
  • <c-w-=>:恢复当前窗口高度
  • <c-w-H/J/K/L>:移动窗口至tab左/下/上/右,占据全部高/宽
  • <c-w-T>:移动窗口至新tab
  • <c-w-r/x>:交换窗口位置(具体逻辑未知)
  • ZZ:保存退出
  • ZQ:放弃保存退出

Tab

  • [n]gt/gT:下/上一个tab;第n个tab

内容

折叠

  • foldmethod=marker{{{`、`}}}标记折叠区域(各花括号之间无空格)

    • zf:创建折叠(在选中区域前后添加标记)
      • zf[n]G:创建当前行至第n行折叠
      • [n]zf[+]:创建当前行至后n行折叠
      • [n]zf[-]:创建当前行至前n行折叠
    • zd:删除 包含 当前位置折叠
    • zD递归 删除包含当前位置折叠、及子折叠
    • zE:删除窗口中所有折叠
    • za:折叠 toggle
    • zo:折叠展开
    • zc:折叠
  • foldmethod=indent:缩进标记折叠

    • zc:折叠
    • zC递归 折叠
    • zo:展开折叠
    • zO:递归展开折叠
    • [z:移至当前折叠开始
    • ]z:移至当前折叠末尾
    • zj:移至下个折叠开始(包括关闭折叠)
    • zk:移至上个折叠结束(包括开闭折叠)
    • zm:提高折叠水平,即依次折叠当前最高水平缩进
    • zr:降低折叠水平,即依次展开当前最高水平缩进
    • zn:禁用折叠
    • zN:启用折叠
  • foldmethod=manual:手动折叠

    • zf<range>:折叠选中区域
      • zf70j:折叠之后70行
      • zfa(:折叠 ( 包围区域
  • mkview:保存折叠状态

  • loadview:载入折叠状态

Vim Cmd常用命令

内容相关

查找

//?

:/foo向下查找,:?foo向上查找

  • set ingorecase时,不敏感查找;set smartcase时,如果 查找中有大写字符则敏感;
  • :/foo\c手动强制大小写不敏感,:/foo\C强制敏感
  • nN重复同向、反向之前查找
:vimgrep

文件间搜索

1
:vim[grep] /pattern/[g][j] files
  • 选项

    • g:全局匹配(匹配每行全部)
    • j:查找完毕后,进更新quickfix列表,光标不跳转
  • files

    • %:当前文件
    • *:当前目录
    • **/*:仅子目录
    • **/xxxx:当前目录及子目录所有满足xxxx模式文件
    • pattern:满足pattern的文件
global
  • [range]范围(默认整个文件)中查找{pattern},标记 匹配行
  • 对匹配行执行命令{command}(默认print命令)
    • 若标记行在被操作之前已经被删除、移动、合并等而消失, 则不对器执行操作
1
:[range]g[lobal][!]/{pattern}/{command}
  • 选项
    • [!]:对不匹配者执行草在
1
2
3
4
5
6
7
8
9
10
11
12
:g/^/m 0
# 将文件反序
:g/^/+1 d
:%normal jdd
# 删除偶数行
:g/^/d|m.
:%normal jkdd
# 删除奇数行
:g!/aaa/d
# 删除不包含`aaa`行
:g/aaa/"ay
# 复制包含`aaa`行至寄存器`"`

替换

:s
1
:[start,end]s/foo/bar[/i][I][g]
  • 替换区域:默认只替换当前行
    • 手动指定具体行号::2,4s/foo/bar(左闭右开)
    • 特殊符号
      • 全文替换%:%s/foo/bar
      • 第一行^:^,4s/foo/bar
      • 当前行.:.,6s/foo/bar
      • 末尾行$:4,$s/foo/bar
    • visual模式下,手动选择区域命令行自动补全为:'<,'>
  • 替换标志
    • 大小写不敏感/i\c:%s/foo/bar/i:%s/foo\c/bar
    • 大小写敏感/I\C%s/foo/bar/I:%s/foo\C/bar
    • 全局替换/g(替换每行全部模式)::%s/foo/bar/g
      • 默认情况下只替换首个模式:foo,foobar被替换为 bar,foobar
      • 全局替换模式下:foo,foobar被替换为bar,barbar
  • 交互(确认)替换::%s/foo/bar/c,每次替换前会询问
  • 超级变量
    • &:代表被替换模式字串

文本移动

>/<
1
2
:[range]>
:[range]<
  • 范围内文本块右、左移动1个shiftwidth
  • 移动num个shiftwidth添加num个>/<
move
1
:[range]m[ove] [n]
  • 移动范围内行至第[n]
1
2
:m0
# 移动当前行至首行
t
1
:[range]t [n]
  • 复制范围内至第[n]
1
2
:t.
# 复制当前行至下行

文件相关

放弃修改、重新加载、保存

  • :w[rite]:保存此次修改
  • :e!:放弃本次修改(和:q!不同在于不会退出vim)
  • :bufdo e!:放弃vim所有已打开文件修改
  • :e:重新加载文件
  • :e#:当前窗口加上个buffer(反复切换)
  • :bufdo e:重新加载vim所有已打开文件
  • :saveas new_file_name:另存为,不删除原文件
  • :sb[n]:split窗口加载第n个buffer
  • :b[n]:当前窗口加载第n个buffer
  • :n[n]:当前窗口加载下/第n个buffer

Window

  • :sp[lit]:水平分割当前窗口,展示当前文件
  • :vs[plit]:竖直分割当前窗口,展示当前文件
  • :new:水平分割当前窗口,新文件
  • :vnew:竖直分割当前窗口,新文件
  • :sview:水平分割当前窗口,只读[缺省当前]文件
  • :[n]winc >/<:水平方侧扩展/收缩
  • :[n]winc +/-:竖直方向扩展/收缩
  • :res+/-[n]:竖直方向扩展/收缩
  • :vertical res+/-[n]:水平方向扩展/收缩
  • :ressize[n]:高度设置为n单位
  • :vertical res[n]:宽度设置为n单位
  • :q[uit][!]:退出当前窗口
    • !:强制退出,修改不保存
  • :close:关闭当前窗口(不能关闭最后窗口)
  • :only:关闭其他窗口
  • :qa:退出所有窗口
  • :wq:保存、退出当前窗口
  • :x:类似于wq,但是未修改则不写入

注:

  • 水平方向:扩张优先左侧变化,收缩右侧变化
  • 竖直方向:扩展收缩均优先下侧变化

Tab

  • :tabnew [opt] [cmd] [file_name]:打开新tab
  • :tabc:关闭当前tab
  • :tabo:关闭其他tab
  • :tabs:vim cmd区域查看所有打开的tab信息
  • :tabp:查看前一个tab
  • :tabfirst/:tablast:第一个/最后一个tab
  • :tabn [num]:查看下一个/第num个tab

Diff

  • :diffsplit [filename]:上下分割窗口和当前窗口比较

    • 默认同当前文件进行diff
  • :difft:将当前窗口变为比较窗口

    • 若没有其他比较窗口,则没有明显变化
    • 若存在其他比较窗口,则加入比较
  • :diffu[pdate][!]:更新当前比较窗口

    • 比较状态下修改当前文件后,重新生成比较信息
    • !:重新载入文件后更新(外部修改文件)
  • :diffo[!]:关闭当前窗口比较状态

    • !:关闭所有窗口比较状态

Session

  • :mksession[!] <session-file-name>:将当前状态写入 session 文件
  • :source <session-file-name>:载入已有 session 文件

其他

多行语句

“|”管道符可以用于隔开多个命令:echom "bar" | echom "foo"

:vertical

:vertical基本可以用所和窗口有关命令之前,表示左右(分割)

  • :vert split/:vs:左右分割窗口
  • :vert sb[n]:左右分割窗口载入buff[n]
  • :vert diffs file_name:左右分割窗口diffs
  • :vert res +/-[n]:调整窗口大小

其他CMD命令

编辑过程中使用shell

  • :!{shell command}即可直接执行shell命令并暂时跳出vim

    • :r !{shell command}可以将输出结果读取到当前编辑
    • :w !{sheel command}可以将输出结果输出到vim命令行
  • :shell即可暂时进入到shell环境中,$exit即可回到vim中

  • <c-z>暂时后台挂起vim回到shell环境中,$fg即可回到之前 挂起的进程(此时为vim,详见fg命令)

读取结果

  • :read cmd:读取cmd结果至光标下一行
    • :read !date:读取系统date命令结果

交换文件处理

  • 确认需要恢复:直接恢复R

  • 确认丢弃:直接删除D

  • 没有明确目标:只读打开O

  • 比较交换文件、现在文件差别

    • 恢复打开R
    • 另存为其他文件:saveas filname.bak
    • 与当前文件对比:diffsplit filename
  • 一般不会直接Eedit anyway

Vim命令行参数

vim

  • $ vim [filname]:打开一般窗口
    • -r [filename]:常看交换文件(特定文件对应交换文件)
    • -R [filename]:只读方式打开文件
    • -S session-file:打开session的方式启动vim
      • 需要 :mksession[!] <session-file> 先创建 session 文件

vimdiff

  • $ vimdiff [file1] [file2]:打开比较窗口
    • -u:合并模式比较
    • -c:上下文模式比较
  • 后面两个模型可常用于输出重定向至新文件

Make

Make基础

Make:根据指定的Makefile文件构建新文件

1
2
$ make [-f makefile] [<target>]
# 指定使用某文件中的规则,默认`makefile`/`Makefile`
  • make默认寻找当前目中GNUmakefile/makefile/Makefile 文件作为配置 文件
  • 默认用makefile中首个目标文件作为最终目标文件,否则 使用<target>作为目标文件

Make参数

  • -b/-m:忽略和其他版本make兼容性

  • -B/--always-make:总是更新/重编译所有目标

  • -C <dir>/--directory=<dir>:指定读取makefile的目录, 相当于$ cd <dir> && make

    • 指定多个-C <dir>,make将按次序合并为最终目录
    • -C时,-w选项自动打开
  • --debug[=<options>]:输出make调试信息

    • a:all,输出所有调试信息
    • b:basic,基本信息
    • v:verbose,基本信息之上
    • i:implicit,所有隐含规则
    • j:jobs,执行规则中命令的详细信息,如:PID、返回码
    • m:makefile,make读取、更新、执行makefile的信息
  • -d:等价于--debug=a

  • -e/--environment-overrides:环境变量覆盖makefile中值

  • -f <file>/--file=<file>/--makefile=<file>:指定 makefile

    • 可以多次传递参数-f <filename>,所有makefile合并 传递给make
  • -h/--help:帮助

  • -i/--ignore-errors:忽略执行时所有错误

  • -I <dir>/--include-dir=<dir>:搜索includemakefile 路径

    • 可以多个-I <dir>指定多个目录
  • -j [<jobsum>]/-jobs[=<jobsum>]:指定同时运行命令数

    • 进程数
    • 默认同时运行尽量多命令
    • 多个-j时最后者生效
  • -k/--keep-going:出错不停止运行

    • 若目标生成失败,依赖于其上目标不会继续执行
  • -l <load>/--load-average[=<load>]

  • --max-load[=<load>]:make命令负载

  • -n/--just-print/--dry-run/--recon:仅输出执行 过程中命令序列,不执行

  • -o <file>/--old-file=<file>/--assume-old=<file>: 不重新生成指定的<file>,即使目标依赖其

  • -p/--print-data-base:输出makefile中所有数据:规则、 变量等

    1
    2
    3
    4
    $ make -qp
    # 只想输出信息,不执行makefile
    $ make -p -f /dev/null
    # 查看执行makefile前的预设变量、规则
  • -q/--question:不执行命令、不输出,仅检查指定目标 是否需要更新

    • 0:需要更新
    • 2:有错误发生
  • -r/--no-builtin-rules:禁用make任何隐含规则

  • -R/--no-builtin-variables:禁用make任何作用于变量上 的隐含规则

  • -s/--silent/quiet:禁止显示所有命令输出

  • -S/--no-keep-going/--stop:取消-k作用

  • -t/--touch:修改目标日期为最新,即组织生成目标的命令 执行

  • -v/--version:版本

  • -w/--print-directory:输出运行makefile之前、之后信息

    • 对跟踪嵌套式调用make有用
  • --no-print-directory:禁止-w选项

  • -W <file>/--what-if=<file>/--new-file=<file>/--assume-file=<file>

    • 联合-n选项,输出目标更新时的运行动作
    • 没有-n,修改<file>为当前时间
  • --warn-undefined-variables:有未定义变量是输出警告信息

步骤

  • 读入所有makefile
  • 读入被include其他makefile
  • 初始化(展开)文件中变量、函数,计算条件表达式
  • 展开模式规则%、推导隐式规则、分析所并规则
  • 为所有目标文件创建依赖关系链
  • 根据依赖关系,决定需要重新生成的目标
  • 执行生成命令

相关环境变量

  • MAKEFILES:make会将此环境变量中的文件自动include

    • 不建议使用,会影响所有的make动作
    • 其中文件缺失不会报错
  • MAKEFLAGS:make命令行参数,自动作为make参数

Makefile基本语法

控制符号

  • #:注释

  • @:消除echoing,默认make会打印每条命令

  • -:忽略命令出错

  • 通配符同bash

    • *:任意字符
    • ?:单个字符
    • [...]:候选字符
    • ~:用户目录
      • ~:当前用户目录
      • ~xxx:用户xx目录
  • %:模式匹配

    1
    2
    %.o: %.c
    # 匹配所有c文件,目标为`.o`文件
  • $:引用、展开变量,执行函数

引用其他Makefile

1
include <filename>
  • <filename>可以是默认shell的文件模式,包含通配符、路径
  • include之前可以有空格,但是不能有<tab>(命令提示)
  • make寻找其他makefile,将其内容放当前位置

  • 若文件没有明确指明为绝对路径、相对路径,make会在以下目录 中寻找

    • -I--include-dir参数
    • /usr/local/bin/include/usr/include
  • make会include环境变量MAKEFILES中文件

    • 不建议使用环境变量MAKEFILES,会影响所有make
  • 文件未找到,make会生成一条警告信息,但继续载入其他文件, 完成makefile读取之后,make会重试寻找文件,失败报错

    • 可以使用-include/sinclude代替,忽略include过程 中的任何错误

Makefile显式规则

1
2
<target>: <prerequisite>
[tab]<commands>
  • <target>:目标
  • <prerequisites>:前置条件
  • <commands>:命令,和前置条件至少存在一个
1
2
a.txt: b.txt c.txt
cat b.txt c.txt > a.txt
  • makefile中规则是生成目标的规则

  • make自顶向下寻找可以用于生成目标的规则,生成最终目标类似 调用函数栈

    • 前置条件/依赖类似于被调用函数
    • 命令类似于函数体
    • 目标类似于函数返回值

Target

目标:make的目标

  • 目标通常是文件名,指明需要构建的对象
    • 文件名可以是多个,之间使用空格分隔
  • 不是文件名的目标称为伪目标,视为某种操作

多目标

多目标规则意义是多个目标共享规则依赖、声明命令,并 不是需要同时生成多个目标

  • 需要多目标中的任何一个时,多目标规则就会被应用,其中 命令被执行

  • 每次只生成单独目标的多目标规则,目标之间只是单纯的 可以合并简化规则中的命令

    1
    2
    3
    4
    5
    6
    7
    8
    9
    bigoutput littleoutput: text.g
    generate text.g -$(subst output,,$@) > $@

    # 等价于

    bigoutput: text.g
    generate text.g -big > bigoutput
    littleoutput: text.g
    generate text.g -little > littleoutput
  • 同时生成多个目标的多目标规则,多个目标应该满足 需要同时生成、不能单独修改,否则没有必要定义为多目标 ,当然这其实也是合并简化规则中的命令

    1
    2
    %.tab.c %.tab.h: %.y
    bison -d $<

Phony Target

todo

伪目标:目标是某个操作的名字,每次执行都会执行命令

1
2
3
4
.PHONY: clean
# 明确声明是*伪目标*,可省略
clean:
rm *.o
  • 若省略.PYHONY,要求当前目中不存在同名文件,否则make 认为目标已存在,不会执行命令

GNU规范

GNU推荐makefile中包含的伪目标、命名

  • all:编译所有目标
  • clean:删除所有被make创建的文件
  • install:安装已编译好程序,即将目标执行文件拷贝到指定 目标中
  • print:列出改变过的源文件
  • tar:打包源程序备份
  • dist:创建压缩文件
  • tags:更新所有目标,以备完整地编译使用
  • check/test:测试makefile流程

静态库

目标archive(member):指定静态库文件、及其组成

  • 这种定义目标的方法就是方便ar命令
1
2
3
4
5
6
7
8
9
10
11
12
13
foolib(hack.o kludge.o): hack.o kludge.o
ar cr foolib hack.o kludge.o

foolib(hack.o): hack.o
ar cr foolib hack.l kudge.o
foolib(kludge.o): kludge.o
ar cr foolib kludge.o

# 确实等价,但是这个看起来有点不对劲,只要传了任何一个
# 静态库的构成,就执行命令???

foolib(*.o): hack.o kludge.o
# 这样更好???

Prerequisites

前置条件/依赖:生成目标的依赖

  • 通常是一组空格分隔的文件名,为空则说明目标的生成和其他 文件无关

  • 指定目标是否重新构建的判断标准,只要有一个前置文件不存在 、有过更新(时间戳比较),目标就需要更新

  • 若前置文件不存在,则需要建立以其作为目标的规则用于生成, make target时会自动调用

1
2
source: file1 file2 file3
# 利用伪目标+前置条件,同时构建多个文件

Commands

命令:更新、构建文件的方法

  • 在linux下默认使用环境变量SHELL/bin/sh)执行命令,
  • 在MS-DOS下没有SHELL环境变量,会在PATH环境变量中寻找 ,并自动加上.exe.bat.sh等后缀

<tab>

每行命令前必须有一个<tab>,否则需要使用提前声明

1
2
3
.RECIPEPREFIX=>
all:
> echo Hello, world

Shell进程

每行命令在单独的shell进程中执行,其间没有继承关系 (即使是同一个规则中)

  • 多条命令可以使用;分隔

    1
    2
    var-kept:
    export foo=bar; echo "foo=[$$foo]"
  • 可类似python\换行

    1
    2
    3
    var-kept:
    export foo=bar; \
    echo "foo=[$$foo]"
  • 使用.ONESHELL命令

    1
    2
    3
    4
    .ONESHELL
    var-kept:
    export foo=bar
    echo "foo=[$$foo]"

嵌套执行Make

大工程中不同模块、功能源文件一般存放在不同目录,可以为每个 目录单独建立makefile

  • 利于维护makefile,使得其更简洁
  • 利于分块/分段编译
  • 最顶层、调用make执行其他makefile的makefile称为总控
1
2
3
4
5
6
7
8
9
10
subsystem:
cd subdir && $(MAKE)
# 等价
subsystem:
$(MAKE) -C subdir

subsystem:
cd subdir && $(MAKE) -w MAKEFLAGS=
# 将命令行参数`MAKEFLAGS`置空,实现其不向下级传递
# 指定`-w`参数输出make开始前、后信息

搜索路径

VPATH

VPATH:makefile中定义的特殊环境变量,指明寻找依赖文件、 目标文件的路径

1
VPATH = src:../src
  • :分隔路径
  • 当前目录优先级依旧最高

vpath

vpath:make关键字,指定不同模式文件不同搜索目录

1
2
3
4
5
6
7
vpath <pattern> <directories>
vpath %.h ../headers
# 指明`<pattern>`模式文件搜索目录
vpath <pattern>
# 清除`<pattern>`模式文件搜索目录设置
vpath
# 清除所有`vapth`设置
  • <pattern>中使用%匹配0或若干字符
  • vpath可以重复为某个模式指定不同搜索策略,按照出现顺序 先后执行搜索

隐含规则

  • 隐含规则是一种惯例,在makefile中没有书写相关规则时自动 照其运行

    • 隐含规则中优先级越高的约经常被使用
    • 甚至有些时候,显式指明的目标依赖都会被make忽略
      1
      2
      3
      4
      foo.o: foo.p
      # Pascal规则出现在C规则之后
      # 若当前目录下存在foo.c文件,C隐含规则生效,生成
      # foo.o,显式依赖被忽略
    • 很多规则使用后缀规则定义,即使使用-r参数,其 仍会生效
  • 隐含规则会使用系统变量

    • CPPFLAGS/CFLAGS:C++/C编译时参数
  • 可以通过模式规则自定义隐含规则,更智能、清晰

    • 后缀规则有更好的兼容性,但限制更多

常用隐含规则

编译C

  • 目标:<n>.o

  • 依赖包含:<n>.c

  • 生成命令

    1
    $(CC) -c $(CPPFLAGS) $(CFLAGS)

编译CPP

  • 目标:<n>.o

  • 依赖包含<n>.cc/<n>.c

  • 生成命令

    1
    $(CXX) -c $(CPPFLAGS) $(CFLAGS)

编译Pascal

  • 目标:<n>.p

  • 依赖包含:<n>.p

  • 生成命令

    1
    $(PC) -c $(PFLAGS)

编译Fortran/Ratfor

  • 目标:<n>.o

  • 依赖包含:<n>.f/<n>.r

  • 生成命令

    1
    2
    3
    4
    5
    6
    $(FC) -c $(FFLAGS)
    # `.f`
    $(FC) -c $(FFLAGS) $(CPPFLAGS)
    # `.F`
    $(FC) -c $(FFLAGS) $(RFLAGS)
    # `.r`

预处理Fortran/Ratfor

  • 目标:<n>.f

  • 依赖包含:<r>.r/<n>.F

  • 生成命令

    1
    2
    3
    4
    $(FC) -F $(CPPFLAGS) $(FFLAGS)
    # `.F`
    $(FC) -F $(FFLAGS) $(RFLAGS)
    # `.r`
  • 转换Ratfor、有预处理的Fortran至标准Fortran

编译Modula-2

  • 目标:<n>.sym/<n>.o

  • 依赖包含:<n>.def/<n>.mod

  • 生成命令
    1
    2
    3
    4
    $(M2C) $(M2FLAGS) $(DEFFLAGS)
    # `.def`
    $(M2C) $(M2FLAGS) $(MODFLAGS)
    # `.mod`

汇编汇编

  • 目标:<n>.o

  • 依赖包含:<n>.s

  • 生成命令:默认使用编译器as

    1
    2
    $(AS) $(ASFLAGS)
    # `.s`

预处理

  • 目标:<n>.s

  • 依赖包含:<n>.S

  • 生成命令:默认使用预处理器cpp

    1
    2
    $(CPP) $(ASFLAGS)
    # `.S`

链接object

  • 目标:<n>

  • 依赖包含:<n>.o

  • 生成命令:默认使用C工具链中链接程序ld

    1
    $(CC) <n>.o $(LOADLIBS) $(LDLIBS)

Yacc C

  • 目标:<n>.c

  • 依赖包含:<n>.y

  • 生成命令

    1
    $(YACC) $(YFALGS)

Lex C

  • 目标:<n>.c

  • 依赖包含:<n>.c

  • 生成命令

    1
    $(LEX) $(LFLAGS)

Lex Ratfor

  • 目标:<n>.r

  • 依赖包含:<n>.l

  • 生成命令

    1
    $(LEX) $(LFLAGS)

创建Lint库

  • 目标:<n>.ln

  • 依赖包含:<n>.c/<n>.y/<n>.l

  • 生成命令

    1
    $(LINT) $(LINTFLAGS) $(CPPFLAGS) -i

创建静态链接库

  • 目标:<archive>(member.o)

  • 依赖包含:member

  • 生成命令

    1
    ar cr <archive> member.o
  • 即使目标传递多个memeber.o,隐含规则也只会解析出把首个 .o文件添加进静态链接库中的命令
1
2
3
4
(%.o): %.o
$(AR) rv $@ $*.o
# 此命令可以得到添加所有`member.o`的命令
# 但是此时`$*=member.o member`

隐含规则使用变量

隐含规则使用的变量基本都是预先设置的变量

  • makefile中改变
  • make命令环境变量传入
  • 设置环境变量
  • -R/--no-builtin-variable参数取消变量对隐含规则作用

命令

  • AR:函数打包程序,默认ar
  • AS:汇编语言编译程序,默认as
  • CC:C语言编译程序,默认cc
  • CXX:C++语言编译程序,默认c++/g++
  • CPP:C程序预处理器,默认$(CC) -E/cpp
  • FC:Fortran、Ratfor编译器、预处理程序,默认f77
  • PC:Pascal语言编译程序,默认pc
  • LEX:Lex文法分析器程序(针对C、Ratfor),默认lex
  • YACC:Yacc文法分析器程序(针对C、Ratfor),默认 yacc -r
  • GET:从SCCS文件中扩展文件程序,默认get
  • CO:从RCS文件中扩展文件程序,默认co
  • MAKEINFO:转换Texinfo .texi到Info程序,默认 makeinfo
  • TEX:转换TeX至Tex DVI程序,默认tex
  • TEXI2DVI:转换Texinfo至Tex DVI程序,默认texi2dvi
  • WEAVE:转换Web至TeX程序,默认weave
  • TANGLE:转换Web至Pascal程序,默认tangle
  • CTANGEL:转换C Web至C,默认ctangle
  • RM:删除文件命令,默认rm -f

命令参数

未指明默认值则为空

  • ARFLAGS:静态链接库打包程序AR参数,默认rv
  • ASFLAGS:汇编语言汇编器参数
  • CFLAGS:C编译器参数
  • CXXFLAGS:C++编译器参数
  • CPPFLAGS:C预处理参数
  • LDFLAGS:链接器参数
  • FFLAGS:Fortran编译器参数
  • RFLAGS:Fatfor的Fortran编译器参数
  • LFLAGS:Lex文法分析器参数
  • YFLAGS:Yacc文法分析器参数
  • COFLAGS:RCS命令参数
  • GFLAGS:SCCS get参数

隐含规则链

make会努力自动推导生成目标的一切方法,无论中间目标 数量,都会将显式规则、隐含规则结合分析以生成目标

  • 中间目标不存在才会引发中间规则

  • 目标成功产生后,中间目标文件被删除

    • 可以使用.SECONDARY强制声明阻止make删除该中间目标
    • 指定某模式为伪目标.PRECIOUS的依赖目标,以保存被 隐含规则生成的符合该模式中间文件
  • 通常makefile中指定成目标、依赖目标的文件不被当作中间目标 ,可以用.INTERMEDIATE强制声明目标(文件)是中间目标

  • make会优化特殊的隐含规则从而不生成中间文件,如从文件 foo.c直接生成可执行文件foo

模式规则

模式规则:隐式规则可以看作内置模式规则

  • 目标定义包含%,表示任意长度非空字符串
  • 依赖中同样可以使用%,但是其取值取决于目标
  • 命令中不使用模式%,使用自动化变量
  • 模式规则没有确定目标,不能作为最终make目标

    • 但是符合模式规则的某个具体文件可以作为最终目标
    • 不需要作为显式规则的目标,如:archive(member)作为 静态库隐含规则目标
  • 模式的启用取决于其目标%解析同样取决于目标 (因为根据目标查找、应用模式规则)

  • 模式规则类似于隐含规则,给出符合某个模式的某类目标 的依赖、生成命令

  • %展开发生在变量、函数展开后,发生在运行时

静态模式

静态模式:给定目标候选范围的模式,限制规则只能应用在以 给定范围文件作为目标的情况

1
2
<target>: <target-pattern>: <prereq-patterns>
<commands>
  • <target>:目标候选范围,可含有通配符
  • <target-pattern>所有目标文件满足的模式
  • <prereq-pattern>:目标相应依赖
  • 简单例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    objects = foo.o bar.o
    all: $(objects)
    $(objects): %.o: %.c
    $(CC) -c $(CFLAGS) $< -o $@

    # 等价于

    foo.o: foo.c
    $(CC) -c $(CFLAGS) foo.c -o foo.o
    bar.o: bar.c
    $(CC) -c $(CFLAGS) bar.c -o bar.o
  • 静态模式+filter函数筛选范围

    1
    2
    3
    4
    5
    files = foo.elc bar.o lose.o
    $(filter %.o,$(files)): %.o: %.c
    $(CC) -c $(CFLAGS) $< -o $@
    $(filter %.elc,$(files)): %.elc: %.el
    emacs -f batch-byte-compile $<

重载内建隐含规则

1
2
3
4
5
%.o: %c
$(CC) -c $(CPPFLAGS) $(CFLAGS) -D $(date)
# 重载内建隐含规则
%o: %c
# 命令置空,取消内建隐含规则

后缀规则

  • 双后缀规则:定义一对目标文件后缀、依赖后缀
  • 单后缀规则:定义一个依赖后缀
1
2
3
4
5
6
.c.o:
# 等价于`%.o: %c`
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
.c:
# 等价于`%: %.c`
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
  • 后缀规则中不能有任何依赖文件,否则不是后缀规则,后缀被 认为是目标文件

  • 后缀规则中必须有命令,否则没有任何意义,这不会移去内建 的隐含规则

  • 后缀规则定义中的后缀需要是make所认识的,可以使用伪目标 .SUFFIXES修改make认识的后缀

    1
    2
    3
    4
    .SUFFIXES:
    # 删除默认后缀
    .SUFFIXES: .c .o .h
    # 添加自定义后缀
    • 变量$SUFFIXE用于定义默认后缀列表,不应该修改

    • -r/--no-builtin-rules同样会清空默认后缀列表

  • 后缀规则是老式定义隐含规则的方法,会被逐步取代,事实上 后缀规则在makefile载入后会被转换为模式规则

模式规则搜索算法

设目标为src/foo.o

  • 将目标目录部分、文件名部分分离,得到src/foo.o

  • 搜索所有模式规则列表,创建目标和src/foo.o匹配的模式 规则列表

    • 若模式规则列表中有目标匹配所有文件的模式(如%), 则从列表中移除其他模式
    • 移除列表中没有命令的规则
  • 对列表中首个模式规则

    • src/foo.ofoo.o匹配目标,推断%匹配非空部分 茎S
    • 把依赖中%替换为茎S,如果依赖项中没有包含目录, 尝试将src添加在其前
    • 检查所有依赖文件存在、理当存在(文件被定义为其他规则 的目标文件、显式规则的依赖文件)
    • 若有依赖文件存在、理当存在或没有依赖文件,此规则被 采用,退出算法
  • 若没有找到合适模式规则,则检查列表中下个规则是否可行

  • 若没有模式规则可以使用,检查.DEFAULT规则存在性,存在 则应用

变量、赋值

Makefile中定义的变量类似C++/C中的宏

  • 代表一个字符串,在makefile中执行的时候展开在所在位置

    • ""会被作为字符串一部分
    • 默认空格、逗号分隔列表

      1
      2
      3
      4
      5
      empty:=
      space:=$(empty) # 后面有空格,就得到了空格
      comma:=,
      foo:=a,b,c
      bar:=$(substr $(comma), $(space), $(foo)) # 得到字符串`a b c`
  • 变量可以改变值

  • 在shell中需要$$处应使用两个$$$,一个$被escape,则 shell解释时仍然保留一个$,如:变量、函数等都需要

赋值

Makefile内自定义变量

1
2
3
4
5
6
7
txt = Hello World
# 自定义变量
test:
@echo $(txt)
echo ${txt}
# 调用变量,`()`、`{}`含义相同
# 若变量名为单个字符,可以省略括号,但不建议省略
  • =lazy set,在执行时扩展

    • 可以使用任意位置定义(可能还未定义)的变量赋值
    • 允许递归扩展,make报错
  • :=immediate set,在定义/赋值时扩展完毕

    • 只允许使用之前已定义变量赋值(否则为空)
  • ?=set if absent,只有变量为空时才设置值

  • +=append,将值追加到变量的尾部

    • 若前面变量有定义,+=会继承前一次操作符:=/=
    • 对于=定义变量,make自动处理“递归”

define

define可以换行定义变量

  • 变量类似宏的行为、可换行定义变量,方便定义命令包
1
2
3
4
5
6
7
8
9
10
define run-yacc
# `define`后跟变量名作为命令包名称
yacc $(firstword $^); \
mv y.tab.c $@
endef
# 结束定义

foo.c: foo.y
$(run-yacc)
# 使用命令包

override

  • 若变量由make命令行参数-e设置,makefile中默认忽略对其 赋值
  • 需要显式使用override关键字设置
1
2
3
override <variable> = <value>
override <variable> := <value>
override define <variable>

export

上级makefile中变量可以显式export传递到下层makefile中, 但是不会覆盖下层中定义的变量(除指定-e参数)

1
2
3
4
5
6
7
8
9
export <variable>[=value]
# 传递变量至下级makefile中
unexport <variable>
# 禁止变量传递至下级makefile中

export variable = value
# 等价
variable = value
export variable
  • export后面不指定具体传递变量,表示传递所有变量
  • MAKEFLAGSSHELL两个变量总是会传递到下级makefile中

系统环境变量

make运行时系统环境变量、命令行环境变量可以被载入makefile

  • 默认makefile中定义变量覆盖系统环境变量
  • -e参数则表示makefile中变量被覆盖
1
2
3
test:
@echo $$HOME
# 传递给shell的变量,需要`$$` escape

Target-Specific Variable

目标/局部变量:作用范围局限于规则、连带规则中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<target ...>: [override] <variable-assignment>

prog: CFLAGS = -g
prog: prog.o foo.o bar.o
$(CC) $(CFLAGS) prog.o foo.o bar.o

prog.o: prog.c
$(CC) $(CFLAGS) prog.c

foo.o: foo.c
$(CC) $(CFLAGS) foo.c

bar.o: bar.c
$(CC) $(CFLAGS) bar.c

Pattern-Specific Variable

模式变量:给定模式,变量定义在符合模式的所有目标

1
2
3
<pattern ...>: [override]<variable-assignment>

%.o: CFLAGS = -o

Implicit Variables

内置变量:主要是为了跨平台的兼容性

  • $(CC):当前使用的编译器

    1
    2
    output:
    $(CC) -o output input.c
  • $(MAKE):当前使用的Make工具

  • $(MAKECMDGOLA):make目标列表

Automatic Variables

自动化变量:应用规则时被自动赋予相应值(一般是文件)的变量

  • $@当前需要生成的目标文件
    • 多目标规则中,$@也只表示被需要目标
  • $*:匹配符%匹配部分
    • 若目标中没有%模式符,$*不能被推导出,为空
    • GNU make中,目标中没有%$*被推导为除后缀部分, 但是很可能不兼容其他版本,谨慎使用
  • $<:首个前置条件
  • $%:仅当目标是函数库文件,表示目标成员名,否则为空

    • 目标为foo.a(bar.o)$%bar.o$@foo.a
  • $?:比目标更新的前置条件,空格分隔

  • $^:所有前置条件,会取出其中重复项
  • $+:类似于$^,但是剔除重复依赖项
  • 自动化变量只应出现在规则的命令
  • 自动化变量值与当前规则有关
  • 其中$@$*$<$%扩展后只会为单个文件,$?$^$+扩展后可能是多个文件
1
2
3
dest/%.txt: src/%.txt
@[ -d test ] || mkdir dest
cp $< $@

D、F

  • 7个自动化变量可以搭配DF取得相应路径中目录名、 文件名
  • 新版本GNU make可以使用函数dirnotdir代替D/F
  • D/dir:目录带有最后/,若为当前目录则为./
  • F/nodir:文件名
  • 对可能会扩展为多文件的$?$^$+D/F处理后 返回同样是多个目录/文件
1
2
3
4
5
6
7
8
9
10
11
12
13
$(@D)
$(dir $@)
# `$@`的目录名
$(@F)
$(nodir $@)
# `$@`的文件名

$(?D)
$(dir $?)
# `$?`中所有目录,空格分隔
$(?F)
$(nodir $?)
# `$?`中所有文件,空格分隔

控制语句

if

1
2
3
4
5
6
7
8

<conditional-directive>
<text-if-true>
[
else
<text-if-false>
]
endif
  • ifeq:比较参数是否相等

  • ifneq:比较参数是否不等

    1
    2
    3
    4
    5
    6
    ifeq ($(CC), gcc)
    # 也可以用单/双引号括起,省略括号
    libs=$(libs_for_gcc)
    else
    libs=$(normal_libs)
    endif
  • ifdef

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    bar =
    foo = $(bar)
    # `foo`有定义
    ifdef foo
    frobozz = yes
    # 此分支
    else
    frobozz = no
    endif

    foo =
    # `foo`未定义
    ifdef foo
    frobozz = yes
    else
    frobozz = no
    # 此分支
    endif
  • ifndef

  • <conditional-directive>, else, endif行可以有多余空格, 但是不能以<tab>开头,否则被认为是命令
  • make在读取makefile时就计算表达式值、选择语句,所以最好 别把自动化变量放入条件表达式中
  • make不允许把条件语句分拆放入两个文件中

for

1
2
3
4
5
6
7
8
9
10
11
LIST = one two three

all:
for i in $(LIST); do \
echo $$i;
// 这里传递给shell的变量,需要`$$` escape
done
all:
for i in one two three; do
echo $$i;
done

内建函数

1
2
$(function parameters)
${function paremeters}

Make控制函数

提供一些函数控制make执行

  • 检测运行makefile的运行时信息,根据信息决定make继续执行 、停止

error

产生错误并退出make,错误信息<text>

1
2
3
4
5
6
7
8
9
10
$(error <text...>)

ifdef ERROR_001
$(error error is $(ERROR_001))
endif

ERR = $(error found an error)
.PHONY: err
err:
err: ; $(ERR)

warning

类似error函数,输出警告信息,继续make

其他函数

shell

执行shell命令的输出作为函数返回值

1
srcfiles := $(shell echo src/{00..99}.txt)
  • 函数会创建新shell执行命令,大量使用函数可能造成性能下降 ,尤其makefile的隐晦规则可能让shell函数执行次数过多

wildcard

在变量中展开通配符*

1
2
3
srcfiles := $(wildcard src/*.txt)
# 若不展开,则`srcfiles`就只是字符串
# 展开后则表示所有`src/*.txt`文件集合

字符串处理函数

subst

文本替换

1
2
3
4
5
$(subst <from>,<to>,<text>)
# `subst`函数头

$(subst ee,EE,feet on the street)
# 替换成*fEEt on the strEET*

patsubst

模式匹配的替换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$(patsubst <pattern>,<replacement>,<text>)
# 函数头文件
$(patsubst %.c,%o,x.c.c bar.c)
# 替换为`x.c.o bar.o`

foo := a.o b.o c.o
$(variable: <pattern>=<replacement>)
# `patsubst`函数的简写形式
bar := $(foo:%.o=%.c)
# `$(bar)`变为`a.c b.c c.c`

$(variable: <suffix>=<replacement>)
# 没有模式匹配符`%`则替换结尾
bar := $(foo:.o=.c)
# `$(bar)`变为`a.c b.c c.c`

strip

去字符串头、尾空格

1
2
$(strip <string>)
$(strip a b c)

findstring

<in>中查找<find>,找到返回<find>,否则返回空串

1
2
$(findstring <find>,<in>)
$(findstring a,a b c)

filter

<pattern>模式过滤<text>字符串中单词,返回符合模式的 单词

1
2
3
4
5
6
$(filter <pattern..>,<text>)

sources := foo.c bar.c baz.s ugh.h
foo: $(sources)
cc $(filter %.c %.s, $(sources)) -o foo
# 返回`foo.c bar.c baz.s`

filter-out

<pattern>模式过滤<text>字符串中单词,返回不符合模式的 单词

1
2
3
4
objects := main1.o foo.o main2.o bar.o
mains=main1.o main2.o
$(filter-out $(mains), $(objects))
# 返回`foo.o bar.o`

sort

<list>中单词升序排序

1
2
3
4
$(sort <list>)

$(sort foo bar lose)
# 返回`bar foo lose`

word

取字符串<text>中第<n>个单词

1
2
3
4
$(word <n>,<text>)

$(word 2, foo bar baz)
# 返回`bar`

wordlist

<text>中取<s>-<e>单词(闭区间)

1
2
3
4
$(wordlist <s>,<e>,<text>)

$(wordlist 2, 3, foo bar baz)
# 返回`bar baz`

words

统计<text>中单词个数

1
2
3
4
$(word <text>)

$(word, foo bar baz)
# 返回3

firstword

<text>中首个单词

1
2
3
4
$(firstword <text>)

$(firstword foo bar)
# 返回`foo`

文件名操作函数

dir

从文件名序列中取出目录部分

  • 最后/之前部分
  • 若没有/则返回./
1
2
3
4
$(dir <names...>)

$(dir src/foo.c hacks)
# 返回`src/ ./`

notdir

从文件名序列中取出非目录部分(最后/之后部分)

1
2
3
4
$(notdir <names...>)

$(notdir src/foo.c hacks)
# 返回`foo.c hacks`

suffix

从文件名序列中取出各文件名后缀

1
2
3
4
$(suffix <names...>)

$(suffix src/foo.c src-1.0/bar.c hacks)
# 返回`.c .c`

basename

从文件名序列中取出各文件名“前缀”(除后缀外部分)

1
2
3
4
$(basename <names...>)

$(basename src/foo.c src-1.0/bar.c hacks)
# 返回`src/foo src-1.o/bar hacks`

addsuffix

把后缀<suffix>添加到文件名序列中每个单词后

1
2
3
4
$(addsuffix <suffix>,<names...>)

$(addsuffix .c, foo bar)
# 返回`foo.c bar.c`

addprefix

把后缀<prefix>添加到文件名序列中每个单词后

1
2
3
4
$(addprefix <prefix>,<names...>)

$(addprefix src/, foo bar)
# 返回`src/foo src/bar`

join

<list2>中单词对应添加到<list1>中单词后

  • 较多者剩余单词保留
1
2
3
4
$(join <list1>,<list2>)

$(join aaa bbb, 111 222 333)
# 返回`aaa111 bbb222 333`

控制函数

foreach

循环函数,类似于Bash中的for语句

  • <list>中单词逐一取出放到参数<var>所指定的变量中
  • 再执行<text>所包含的表达式,每次返回一个字符串
  • 循环结束时,返回空格分隔的整个字符串
1
2
3
4
5
$(foreach <var>,<list>,<text>)

names := a b c d
files := $(foreach n,$(names),$(n).o)
# 返回`a.o b.o c.o d.o`
  • <var>是临时局部变,函数执行完后将不再作用

if

类似于make中的ifeq

  • <condition>为真(非空字符串),计算<then-part>返回值
  • <condition>为假(空字符串),计算<else-part>、返回空 字符串
1
$(if <condition>,<then-part>,[<else-part>])

call

创建新的参数化函数的函数

  • 创建表达式<expression>,其中可以定义很多参数
  • call函数向其中传递参数,<expression>返回值即call 返回值
1
2
3
4
5
6
7
8
$(call <expression>,<param1>,<param2>,...>

reverse = $(1) $(2)
foo = $(call reverse,a,b)
# 返回`a b`
reverse = $(2) $(1)
foo = $(call reverse,a,b)
# 返回`b a`
  • <expression>要先创建为变量,然后不带$传递

origin

返回变量的来源

  • undefined<variable>未定义
  • default:make默认定义变量
  • environment:环境变量,且-e选项未开
  • file:定义在makefile中
  • command line:命令行定义环境变量
  • overrideoverride关键字定义
  • atomatic:命令运行中自动化变量
1
2
3
4
5
6
7
$(origin <variable>)

ifdef bletch
ifeq "$(origin bletch)" "environment"
bletch = barf, gag, etc
endif
endif
  • <variable>不操作变量值,不带$传递

Makefile技巧

案例

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
edit: main.o kdd.o command.o display.o \
insert.o search.o files.o utils.o
cc -o edit main.o kbd.o command.o dispaly.o\
insert.o search.o files.o utils.o

main: main.c defs.h
cc -c main.c
kbd.o: kbd.c defs.h
cc -c kbd.c
command.o: command.c defs.h command.h
cc -c command.c
display.o: display.o defs.h buffer.h
cc -c display.c
insert.o: insert.c defs.h buffer.h
cc -c insert.c
search.o: search.c defs.h buffer.h
cc -c search.c
files.o: files.c defs.h buffer.h command.h
cc -c files.c
utils.o utils.c defs.h
cc -c utils.c

clean:
rm edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o

.PHONY: edit clean
# 设置`edit`、`clean`为伪目标

利用变量简化目标

1
2
3
4
5
6
objects = main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o

edit: $(objects)
cc -o edit $(objects)
# 以下同上

隐式模式自动推导

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
objects = main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
edit: $(objects)
cc -o edit $(objects)
main.o: defs.h
kbd.o: defs.h command.h
command.o: defs.h command.h
display: defs.h buffer.h
insert.o: defs.h buffer.h
search.o: defs.h buffer.h
files.o: defs.h buffer.h command.h
utils.o: defs.h

clean:
rm edit $(objects)

.PHONY: clean
  • 利用隐式模式自动推导文件、文件依赖关系

利用变量提取依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
objects = main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
edit: $(objects)
cc -o edit $(objects)

$(objects): defs.h
kbd.o command.o files.o: command.h
display.o insert.o search.o files.o: buffer.h

clean:
rm edit $(objects)

.PHONY: clean
  • 文件变得简单,但是依赖关系不再清晰

自动生成依赖

  • 大部分C++/C编译器支持-M选项,自动寻找源文件中包含的 头文件,生成依赖关系

  • GNU建议为每个源文件自动生成依赖关系,存放在一个文件中, 可以让make自动更新依赖关系文件.d,并包含在makefile中

1
2
3
4
5
6
7
8
9
10
11
12
13
%.d: %.c
@set -e; rm -f $@; \
$(cc) -M $(CPPFLAGS) $< > $@.$$$$; \
# 生成中间文件
# `$$$$`表示4位随机数
sed 's,/($*/)/.o[ :]*,/1.o $@ : ,g' < $@.$$$$ > $@; \
# 用`sed`替换中间文件target
# `xxx.o` -> `xxx.o xxx.d`
rm -f $@.$$$$
# 删除中间文件

source = foo.c bar.c
include $(sources: .c=.d)

Git 基础

.gitingore

.gitignore忽略规则

  • !开头:排除应被忽略

  • /结尾:忽略文件夹

  • /开头:git仓库根目录路径开始(可省略)

  • 遵循一定的正则表达式

    • *:多个字符,不包括/,因此多层级目录需要一一指定
    • ?:单个字符
    • []:匹配其中候选字符

.gitignore配置方式

  • 仓库根目录创建.gitignore文件,添加忽略规则

    • 忽略规则针对当前项目
    • .gitignore文件默认随仓库分发,所有人共用忽略规则 (当然可以在.gitignore中配置忽略.gitignore
  • 设置全局忽略文件,对所有git项目适用

    1
    git config --global core.excludesfile /path/to/.gitignore
  • 修改.git/info/exclude文件,添加忽略规则

    • 对单一项目有效
    • 非所有人共用忽略规则

Git配置/config

  • 配置文件、配置类型

    • --system:系统全局配置,配置文件/etc/gitconfig
    • --global:用户全局配置,配置文件 $HOME/.gitconfig$HOME/.config/git/config
    • --local:局部repo配置,配置文件repo/.git/config
    1
    2
    3
    4
    # 修改`section.key`值(缺省`--local`)
    $ git config [--system|--global|--local] <section>.<key> <value>
    # 删除配置项
    $ git config [--system|--global|--local] --unset <section>.<key>

配置文件常用

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
 # 核心修改
[core]
# 忽略文件权限修改
filemode = false
editor = vim
# 提交、检出时换行符设置
# `input`:提交时转换为`<LF>`、检出时不转换
# `false`:提交、检出均不转换
# `true`:提交时转换为`<LF>`、检出时转换为`<CRLF>`
autocrlf = input
# 是否允许文件混用换行符
# `true`:拒绝提交包含混合换行符文件
# `false`:允许提交包含混合换行符文件
# `warn`:提交包含混合换行符文件时警告
safecrlf = true
[user]
name = xyy15926
email = xyy15926@163.com
# 设置别名
[alias]
st = status
ci = commit
br = branch
lg = "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
d = difftool
# 输出着色
[color]
# 打开所有默认终端着色
ui = true
[diff]
tool = vimdiff
[difftool]
prompt = false
  • autocrlf在linux若设置为input,在add包含<CRLF> 文件会报fatal
    • 因为input在提交时会将<CRLF>转换为<LF>,但在 检出时无操作
    • 所以导致即使add也不能保证repo当前状态和提交状态 一致

remote

1
2
3
4
 # 查看远程仓库
$ git remote -v
# 设置远程仓库地址
$ git remote set-url <repo_name> <new_url>

指定ssh key

  • git依赖ssh进行存储库认证,无法直接告诉git使用哪个私钥
  • ~/.ssh/config中配置ssh host:git每次使用host代替原 服务器地址

    1
    2
    3
    4
    host <host>
    HostName github.com
    IdentityFile $HOME/.ssh/id_rsa_github_private
    User git
    • ssh host详见*linux/shell/config_files”
  • GIT_SSH_COMMAND环境变量:指定ssh命令-i中参数

    1
    2
    3
    4
    5
    GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa_github_private" git clone ...
    // 可以`export`持久化
    export GIT_SSH_COMMAND = ...
    // 写入git配置
    git config core.sshCommand "..."

展示命令

log

1
2
$ git log [<file_name>]
# 查看文件提交历史

show

1
2
$ git show <tag_no|commit_hash>
# 查看改动内容

Tmux

Tmux

  • Session:用户与计算计算机的交互

    • 一般而言,temrinal窗口、Session进程绑定
      • 打开窗口,Session开始
      • 关闭窗口,Session结束
  • Tmux:终端复用软件,将terminal窗口、Session解绑

    • 允许多个窗口接入、断开多个Session
      • 新增多个Session
      • 接入已有Session,共享Session
    • 支持窗口竖直、水平拆分

https://man7.org/linux/man-pages/man1/tmux.1.html

命令行参数

  • -S <socket-file>:指定tmux使用socket文件(位置)

Session管理

  • tmux new -s <session-name>:创建指定名称session
    • 缺省数字命名
  • tmux detach:detach当前接入会话
  • tmux ls/list-session:列出session列表
  • tmux rename -t <s1> <s2>:重命名session
  • tmux a [-t <session-name>]:attach指定session
    • 缺省连接上个session
  • tmux switch -t <session-name>:切换至指定session
  • tmux kill-session [[-a] -t s1]:关闭session
    • 缺省关闭上次session
    • -a:关闭除指定session外其他session
  • tmux kill-server:关闭所有session

Tab(Windows)管理

  • tmux new-window [-n <win-name>]:创建新窗口
  • tmux switch-window -t <win-name>:切换到指定窗口
  • tmux rename-window <win-name>:重命名当前窗口

Pane管理

  • tmux split-window [-h]:竖直/水平划分窗口
  • tmux select-pane -U/-D/-L/-R:激活上、下、左、右侧Pane
  • tmux swap-pange -U/-D/-L/-R:当前Pane上、下、左、右 移动

帮助

  • tmux list-key:列出所有绑定键
  • tmux list-command:列出所有命令
  • tmux info:列出当前所有Tmux会话信息
  • tmux source-file <tmux-conf>:重新加载Tmux配置文件

配置

set

  • 默认配置文件为~/.tmux.conf
  • set[-option] [-g] [-a]:session选项

    • 全局、追加标志
      • -g:全局设置
      • -a:追加设置,适合option需要字符串、样式值
    • default-terminal
    • display-time
    • escape-time
    • history-limit
    • base-index
    • pane-base-index
  • setw/set-window-option [-g] [-a]:window选项

    • 全局、追加标志同set[-option]
    • allow-rename
    • mode-keys:快捷键模式,可以设置为vi
    • synchronize-panes
  • set[-option] -s:server选项

StatusBar设置

  • StatusBar主要由5部分组成

    • windows列表
      • windows-status-*:默认windows
      • windows-status-current-*:当前windows
      • windows-status-bell-*:后台有活动windows (需开启支持)
    • 左侧显示区
    • 右侧显示区
    • message显示条:占据整个status bar
    • command输入条:占据整个status bar
  • *-style bg=<color>,fg=<color>,<ATTR>指定样式

    • 颜色可以用名称、colour[0-255]#RGB方式指定
    • 属性包括(前加no表关闭)
      • bright
      • dim
      • underscore
      • blink
      • reverse
      • hidden
      • italics
      • strikethrough
  • *-format:设置格式

    • #{}中变量名称会被替换为相应值,支持alias缩写的变量 可以省略{}
      • host#H
      • host_short#h
      • pane_id#D
      • pane_index#P
      • pane_title#T
      • session_name#S
      • window_flags#F
        • *:当前窗口
        • -:最后打开的窗口
        • z:Zoom窗口
      • window_index#I
      • window_name#W
    • #()会被作为shell命令执行并被替换
      • 命令执行不会阻塞tmux,而是展示最近一次命令执行 结果
      • 刷新频率由status-interval控制
  • 这里介绍2.9之后配置风格

bind

  • bind[-key] [-n] [-r] <key>:key mapping
    • -n:无需prefix
    • -r:此键可能重复
  • unbind <key>:解绑捕获

默认KeyMappings

  • 快捷键前缀缺省为C-b
  • <prefix>::进入命令行
  • 以下快捷键都是缺省值,可以解绑

Session

  • s:列出session,可用于切换
  • $:重命名session
  • d:detach当前session
  • D:detach指定session

Tab/Windows

  • c:创建新tab
  • &:关闭当前tab
  • ,:重命名当前tab
  • .:修改当前tab索引编号
  • w:列出所有tab
  • n/p/l:进入下个/上个/之前操作tab
  • [tab-n]:切换到指定编号窗口
  • f:根据显示内容搜索tab
  • tmux中window相当于tab

Panes

  • %:水平方向创建窗口
  • ":竖直方向创建窗口
  • Up/Down/Left/Right:根据箭头访问切换窗口
  • q:显示窗口编号
  • o:顺时针切换窗口
  • }/{:与下个/上个窗口交换位置
  • space:在预置面板布局中循环切换
    • even-horizontal
    • even-vertical
    • main-horizontal
    • main-vertical
    • tiled
  • !:将当前窗口置于新tab
  • C-o/M-o:顺/逆时针旋转当前窗口,即所有窗口循环前/后 移动一个位次
  • t:在当前窗口显示时间
  • z:最大/恢复当前窗口
  • i:显示当前窗口信息
  • x:关闭当前窗口
  • q:显示当前窗口编号
  • [:进入自由复制模式,VI 模式下快捷键同 VI,且
    • <space>:从光标处开始选择(支持 V 选择行)
    • <enter>:复制选择部分
  • ]:粘贴
  • tmux中pane相当于vim中windows

信息

  • ?:列出所有绑定键