自动化研究产物 — 并非上游项目。
本仓库是由自动化工具链为拉瓦尔大学(Université Laval)硕士论文构建的一次性实验环境,用于复现已发表的 GitHub Actions 工作流漏洞。它是
skim-rs/skim在提交ca986f444c37d2c1dc15ce1fad2fe101776af8d9(2026-04-14)时的逐字快照,依据该项目自身的许可证重新分发,该许可证文件已原样包含在本快照中。上游项目未参与其中,也从未成为攻击目标,此处研究的漏洞已公开。本仓库中的每个密钥和变量均为随机生成的虚拟值——不存在任何真实凭据。操作引用和运行器镜像均固定为 2026-04-14 时解析到的版本;有关对快照所做的每项更改,请参阅工具链输出中的
pinning.md。如有疑问或异议:[email protected]
人生苦短,用 skim!
我们花费大量时间在文件、代码行和命令之间穿梭。这正是 Skim 的用武之地! 它是一款强大的模糊查找器,旨在让你的工作流程更快、更高效。
Skim 提供一个名为 sk 的单一可执行文件。可以把它视为 grep 等工具的更智能替代品——一旦你尝试过,就会惊叹于没有它的日子是怎么过的!
skim 项目包含以下几个组件:
sk 可执行文件——核心程序sk。有关 Vim 支持,请查看 skim.vim。最新版本的 Fedora 软件包通过非官方的社区维护 COPR 仓库提供。```bash sudo dnf copr enable sisyphus1813/skim sudo dnf install skim
## 手动安装
以下任一方式均可:
- 使用安装脚本:
```sh
# 运行前务必检查脚本内容!
$ curl --proto '=https' --tlsv1.2 -LsSf https://github.com/skim-rs/skim/releases/latest/download/skim-installer.sh | sh
```
- 使用二进制文件:直接[下载 sk 可执行文件](https://github.com/skim-rs/skim/releases)。
- 从 [crates.io](https://crates.io/) 安装:`cargo install skim`
- 手动构建:
```sh
$ git clone --depth 1 [email protected]:skim-rs/skim.git ~/.skim
$ cd ~/.skim
$ cargo build --release
$ # 将生成的 `target/release/sk` 可执行文件添加到你的 PATH 中
```
之后你将可以使用:
- 手册页,你可以将其写入正确路径,或运行 `man --local-file <(sk --man)`
- Shell 补全(以及可选按键绑定),使用 `source <(sk --shell \<shell> \[--shell-bindings])`,详见下文
# 用法
Skim 既可以作为通用过滤器(类似于 `grep`)使用,也可以作为运行命令的交互式界面使用。
## 作为 Vim 插件(在 neovim 上,请查看带 skim 配置文件的 [fzf-lua](https://github.com/ibhagwan/fzf-lua))
通过 vim-plug(推荐):
安装 skim,然后:```vim
Plug 'skim-rs/skim'
以下是一些入门示例:```bash
sk
vim $(find . -name "*.rs" | sk -m)
最后这条命令让你选择扩展名为“.rs”的文件,并在 Vim 中打开所选内容——对开发者来说,这能节省大量时间!
## 作为交互式界面
`skim` 可以动态调用其他命令。通常,你会希望将其与 [grep](https://www.gnu.org/software/grep/)、
[ack](https://github.com/petdance/ack2)、
[ag](https://github.com/ggreer/the_silver_searcher) 或
[rg](https://github.com/BurntSushi/ripgrep) 集成,用于在项目目录中搜索内容:```sh
# works with grep
sk --ansi -i -c 'grep -rI --color=always --line-number {q} .'
# works with ack
sk --ansi -i -c 'ack --color {q}'
# works with ag
sk --ansi -i -c 'ag --color {q}'
# works with rg
sk --ansi -i -c 'rg --color=always --line-number {q}'
注意:在这些示例中,
{q}会被字面展开为当前输入查询(用单引号包裹)。 这意味着这些示例将搜索精确的查询字符串,而非模糊匹配。 如需模糊搜索,请将命令输出通过管道传给sk,而不要使用交互模式。

Fish、Bash 和 Zsh 的绑定位于 shell 目录中:
completion.{shell} 包含用于 sk 命令行使用的补全脚本key-bindings.{shell} 包含按键绑定和 shell 集成:
ctrl-t 通过 sk 选择文件ctrl-r 通过 sk 选择历史记录条目alt-c 通过 sk 选择目录并 cd 进入fish 中不可用)** 用于补全文件路径,例如 ls **<tab> 将显示一个 sk 小部件以选择文件夹要启用这些功能,请根据你的 shell 文档加载 key-bindings.{shell} 文件并设置补全,或参见下文。
你可以使用 --shell 标志为你的首选 shell 生成补全,支持的 shell 包括:bash、zsh、fish、powershell 或 elvish:
source <(sk --shell bash)
source <(sk --shell zsh)
sk --shell fish | source
#### 选项 2:保存到文件,以便在 Shell 启动时自动加载```sh
# For bash, add to ~/.bashrc
echo 'source <(sk --shell bash)' >> ~/.bashrc # Or save to ~/.bash_completion
# For zsh, add to ~/.zshrc
sk --shell zsh > ~/.zfunc/_sk # Create ~/.zfunc directory and add to fpath in ~/.zshrc
# For fish, add to ~/.config/fish/completions/
sk --shell fish > ~/.config/fish/completions/sk.fish
一些常用的按键绑定:
如需完整的按键绑定列表,请参阅 man
page(man sk)。
skim 借用了 fzf 的匹配项语法:
skim 还支持标记的组合。
空格表示 AND 的含义。使用 src main 这一词条时,skim 将搜索
同时匹配 src 和 main 的项。
| 表示 OR(注意 | 两侧的空格)。使用 .md$ | .markdown$ 这一词条时,skim 将搜索以 .md 或
.markdown 结尾的项。
OR 具有更高的优先级。例如,readme .md$ | .markdown$ 被解释为
readme AND (.md$ OR .markdown$)。
如果你更倾向于使用正则表达式,skim 提供了 regex 模式:```sh
sk --regex
您可以通过按 `Ctrl-R`(旋转模式)动态切换到 `regex` 模式。
## 退出代码
| 退出代码 | 含义 |
|-----------|-------------------------------------|
| 0 | 正常退出 |
| 1 | 未找到匹配项 |
| 130 | 由 Ctrl-C/Ctrl-G/ESC 等中止... |
# 与 `skim` 兼容的工具
以下工具与 `skim` 兼容或旨在实现兼容:
## [fzf-lua neovim 插件](https://github.com/ibhagwan/fzf-lua)
一个 [neovim](https://neovim.io) 插件,允许在代码导航中使用 fzf 和 skim。
按照 README 使用您的包管理器进行安装。例如,使用 `lazy.nvim`:```lua
{
"ibhagwan/fzf-lua",
-- enable `sk` support instead of the default `fzf`
opts = {'skim'}
}
一个 nushell 插件,用于实现 skim 与 nushell 之间更好的交互。
按照插件 README 中的说明,你可以使用 cargo 安装它:```nu cargo install nu_plugin_skim plugin add ~/.cargo/bin/nu_plugin_skim
## [sqlite 扩展](https://github.com/tzachar/sqlite_skim)
一个可加载的 `sqlite` 模块,可在 SQL 查询中启用 `skim_score` 函数。
# 自定义
此处文档仅为预览,完整选项列表请查看手册页(`man sk`)。
## 键位映射
使用逗号分隔的键值对来指定绑定(不允许有空格)。例如:```sh
sk --bind 'alt-a:select-all,alt-d:deselect-all'
此外,可使用 + 来串联操作,例如 execute-silent(echo {} | pbcopy)+abort。
有关详细信息,请参阅手册页中的 KEY BINDINGS 部分。
结果共有五个排序键:score, index, begin, end, length。你可以通过 sk --tiebreak score,index,-begin 或任何其他所需顺序来指定记录的排序方式。
你可能有自己的审美偏好!幸运的是,你并不局限于默认外观——Skim 支持对其配色方案进行全面自定义。```sh --color=[BASE_SCHEME][,COLOR:ANSI]
Skim 也遵循 `NO_COLOR` 环境变量。将其设置为任意值后,`sk`(以及许多其他终端应用)将禁用所有彩色输出。更多详情请参阅 [no-color.org](https://no-color.org/)。
### 可用的基础配色方案
Skim 内置了多种配色方案,你可以将其作为起点使用:```sh
sk --color=dark # Default dark theme (256 colors)
sk --color=light # Light theme (256 colors)
sk --color=16 # Simple 16-color theme
sk --color=bw # Minimal black & white theme (no colors, just styles)
sk --color=none # Minimal black & white theme (no colors, no styles)
sk --color=molokai # Molokai-inspired theme (256 colors)
您可以在基础配色方案之后指定颜色值,来自定义各个 UI 元素:```sh sk --color=light,fg:232,bg:255,current_bg:116,info:27
颜色可以通过以下几种方式指定:
- ANSI 颜色(0-255):`sk --color=fg:232,bg:255`
- RGB 十六进制值:`sk --color=fg:#FF0000`(红色文本)
### 可用的颜色自定义选项
以下 UI 元素可以进行自定义:
| 元素 | 描述 | 示例 |
|--------------------|---------------------------------------------|--------------------------------|
| `fg` | 普通文本前景色 | `--color=fg:232` |
| `bg` | 普通文本背景色 | `--color=bg:255` |
| `matched` | 搜索结果中匹配的文本 | `--color=matched:108` |
| `matched_bg` | 匹配文本的背景色 | `--color=matched_bg:0` |
| `current` | 当前行的前景色 | `--color=current:254` |
| `current_bg` | 当前行的背景色 | `--color=current_bg:236` |
| `current_match` | 当前行中匹配的文本 | `--color=current_match:151` |
| `current_match_bg` | 当前行中匹配文本的背景色 | `--color=current_match_bg:236` |
| `spinner` | 进度指示器颜色 | `--color=spinner:148` |
| `info` | 信息行颜色 | `--color=info:144` |
| `prompt` | 提示符颜色 | `--color=prompt:110` |
| `cursor` | 光标颜色 | `--color=cursor:161` |
| `selected` | 选中项标记颜色 | `--color=selected:168` |
| `header` | 标题文本颜色 | `--color=header:109` |
| `border` | 预览/布局的边框颜色 | `--color=border:59` |
### 示例```sh
# Use light theme but change the current line background
sk --color=light,current_bg:24
# Custom theme with multiple colors
sk --color=dark,matched:#00FF00,current:#FFFFFF,current_bg:#000080
# High contrast theme
sk --color=fg:232,bg:255,matched:160,current:255,current_bg:20
有关更多详细信息,请查看手册页(man sk)。
--ansi:解析数据源中的 ANSI 颜色代码(例如,\e[32mABC)--regex:将查询作为正则表达式来匹配数据源在交互模式下,您可以动态调用命令。试试看:```sh sk --ansi -i -c 'rg --color=always --line-number {q}'
### 它是如何工作的?

- Skim 接受两种来源:命令输出或管道输入
- Skim 有两种提示符:用于指定查询模式的查询提示符,以及
用于指定命令“参数”的命令提示符
- `-c` 用于指定要执行的命令,默认为 `SKIM_DEFAULT_COMMAND`
- `-i` 告诉 skim 在启动时打开命令提示符,默认会显示 `c>`。
要进一步缩小命令返回的结果范围,请按
`Ctrl-Q` 切换交互模式。
## 执行外部程序
您可以配置按键绑定,在不退出 Skim 的情况下启动外部进程(`execute`、`execute-silent`)。```sh
# Press F1 to open the file with less without leaving skim
# Press CTRL-Y to copy the line to clipboard and aborts skim (requires pbcopy)
sk --bind 'f1:execute(less -f {}),ctrl-y:execute-silent(echo {} | pbcopy)+abort'
Skim 提供多种算法,完整列表请查看帮助或手册页。其中包括:
skim_v2,默认算法,大致基于 fzf 的算法frizbee,使用 frizbee,来自 blink.cmp neovim 插件中具备防错字能力的算法(仅限 x86_64 和 aarch64)fzy,基于 fzy 的算法并扩展了基本的防错字能力arinae,skim 最新的算法,内部设计时充分考虑了防错字能力,在上述所有算法的基础上进一步扩展,使防错字匹配更自然,同时将逐项性能保持在最佳水准这是 fzf 的一个出色功能,skim 也借鉴了它。例如,我们使用 'ag' 来
查找匹配的行,一旦我们将范围缩小到目标行,我们想通过检查该行周围的上下文来
最终决定选择哪些行。
grep 和 ag 都有 --context 选项,skim 可以利用 --context 来获得
更好的预览窗口。例如:```sh
sk --ansi -i -c 'ag --color {q}' --preview "preview.sh {}"
(注意:[preview.sh](https://github.com/junegunn/fzf.vim/blob/master/bin/preview.sh) 是一个脚本,用于根据文件名:行号:列号打印上下文)
你会得到类似这样的效果:

### 它是如何工作的?
如果通过 `--preview` 选项指定了预览命令,skim 会将 `{}` 替换为当前高亮行(用单引号包围),调用该命令获取输出,并在预览窗口中打印输出。
有时你不需要整行来调用命令。在这种情况下,你可以使用 `{}`、`{1..}`、`{..3}` 或 `{1..5}` 来选择字段。语法在 [字段支持](#filds-support) 部分中说明。
最后,你可能想通过 `--preview-window` 配置预览窗口的位置:
- `--preview-window up:30%` 将窗口放在上方位置,高度为 skim 总高度的 30%。
- `--preview-window left:10:wrap` 指定 `wrap` 允许预览窗口对预览命令的输出进行换行。
- `--preview-window wrap:hidden` 在启动时隐藏预览窗口,之后可以通过 `toggle-preview` 操作显示。
## 字段支持
通常只有插件用户需要理解这一点。
例如,你有一个格式如下的数据源:```sh
<filename>:<line number>:<column number>
然而,你只想在输入查询时搜索 <filename>。也就是说,当你输入 21 时,你希望找到包含 21 的 <filename>,而不是匹配行号或列号。
你可以使用 sk --delimiter ':' --nth 1 来实现这一点。
你也可以使用 --with-nth 来重新排列字段的顺序。
范围语法
<num> -- 指定第 num 个字段,从 1 开始。start.. -- 从第 start 个字段开始,一直到末尾。..end -- 从第 0 个字段开始,一直到第 end 个字段,
包含 end。start..end -- 从第 start 个字段开始,一直到第 end 个
字段,包含 end。Skim 可以在你的 Rust crate 中作为库使用。
首先,将 skim 添加到你的 Cargo.toml 中:```toml
[dependencies]
skim = { version = "", default-features = false, features = [..] }
_功能说明_:
- 使用 `cli` 功能需要将 skim 作为命令行工具使用,当将其作为库使用时*不应*需要该功能。
### 基本用法
然后尝试运行这个简单示例:```rust
extern crate skim;
use skim::prelude::*;
use std::io::Cursor;
pub fn main() {
let options = SkimOptionsBuilder::default()
.height("50%")
.multi(true)
.build()
.unwrap();
let input = "aaaaa\nbbbb\nccc".to_string();
// `SkimItemReader` is a helper to turn any `BufRead` into a stream of `SkimItem`
// `SkimItem` was implemented for `AsRef<str>` by default
let item_reader = SkimItemReader::default();
let items = item_reader.of_bufread(Cursor::new(input));
// `run_with` would read and show items from the stream
let selected_items = Skim::run_with(&options, Some(items))
.map(|out| out.selected_items)
.unwrap_or_else(|| Vec::new());
for item in selected_items.iter() {
println!("{}", item.output());
}
}
你也可以通过使用 tokio 和异步代码,将 skim 作为库进行细粒度使用,从而能够动态地与之交互。
给定一个 Option<SkimItemReceiver>,skim 将相应地读取条目,完成其工作,并将用户选择结果返回给我们,包括所选条目、查询等。请注意:
SkimItemReceiver 是 crossbeam::channel::Receiver<Arc<dyn SkimItem>>提供 SkimItem trait 用于自定义一行的显示、比较和预览方式。它默认针对 AsRef<str> 实现。
此外,SkimItemReader 是一个辅助工具,用于将 BufRead 转换为 SkimItemReceiver(我们可以轻松地将 File 或 String 转换为 BufRead),这样你就可以轻松处理字符串或文件。
请查看 examples/ 目录下的更多示例。
该基准测试在 tmux 会话中运行交互式界面,并等待 UI 稳定。

你可以使用 just bench-plot 生成图表,或在 GNU bash 中手动运行该配方。
Skim 调用 find . 来获取待过滤的文件列表。你可以通过设置环境变量 SKIM_DEFAULT_COMMAND 来覆盖此行为。例如:```sh
$ SKIM_DEFAULT_COMMAND="fd --type f || git ls-tree -r --name-only HEAD || rg --files || find ."
$ sk
你可以把它放进你的 `.bashrc` 或 `.zshrc` 中,如果你希望它默认生效的话。
## 某些文件在 Vim 插件中不显示
如果你使用 Vim 插件并执行 `:SK` 命令,你可能会发现部分
文件没有显示出来。
如 [#3](https://github.com/skim-rs/skim/issues/3) 中所述,在 Vim
插件中,`SKIM_DEFAULT_COMMAND` 默认被设置为该命令:```vim
let $SKIM_DEFAULT_COMMAND = "git ls-tree -r --name-only HEAD || rg --files || ag -l -g \"\" || find ."
这意味着未被 git 识别的文件不会显示。你可以通过 let $SKIM_DEFAULT_COMMAND = '' 覆盖默认设置,或者自行定位缺失的文件。
fzf 是一款用 Go 编写的命令行模糊查找器,而 skim 则尝试用 Rust 实现一款新的同类工具!
本项目是从零开始编写的。部分实现决策与 fzf 有所不同。例如:
skim 具有交互模式。skim 支持预选。更广泛地说,skim 的维护者允许自己在实现上保留一定的自由度。目标是让 skim 的功能与 fzf 一样丰富,但命令行参数可能会有所不同。
如果你遇到任何 bug 或有任何想法,请创建新问题。我们非常欢迎拉取请求。
项目中包含一个 Vagrantfile,用于启动一台无界面的 Windows Server 2022 Core 虚拟机,以便在无需图形界面的情况下测试 Windows 兼容性。它需要你的主机上安装 VirtualBox 和 Vagrant(vagrant 已包含在通过 flake.nix 提供的 Nix 开发环境中)。```sh
vagrant up # First boot: downloads the box and provisions (~15–20 min)
ssh -p 2222 vagrant@localhost # Password: vagrant
在虚拟机内部,项目根目录挂载于 `C:\vagrant`:```powershell
cd C:\vagrant
cargo build
cargo test
后续启动很快——配置仅在首次运行时执行:```sh vagrant halt # Stop the VM vagrant up # Resume vagrant destroy # Delete the VM entirely
# 故障排查
要排查问题,你可以将环境变量 `SKIM_LOG` 或标志 `--log-level` 设置为 `debug` 甚至 `trace`,并将环境变量 `SKIM_LOG_FILE` 或标志 `--log-file` 设置为一个路径。然后你可以在执行期间或之后读取这些日志,以更好地了解发生了什么。如果你需要帮助,请毫不犹豫地将这些日志添加到 issue 中。
## nix、FreeBSD、termux 下无换行符的问题
如果你遇到如下显示问题:```bash
$ for n in {1..10}; do echo "$n"; done | sk
0/10 0/0.> 10/10 10 9 8 7 6 5 4 3 2> 1
例如
你需要将 TERMINFO 或 TERMINFO_DIRS 设置为正确的 terminfo 数据库路径
例如,使用 termux 时,你可以在你的 bashrc 中添加以下内容:``` export TERMINFO=/data/data/com.termux/files/usr/share/terminfo
# 基准测试
## 交互式基准测试(`cli`)
`cli` 基准测试通过在 tmux 会话中运行交互式界面,并轮询状态行直到匹配计数稳定,来对 skim(或任何兼容的二进制文件)与其他版本或 fzf 进行对比测试。这绝非精确或万无一失的测量方法,但其额外好处在于能够与 `fzf` 进行对比基准测试,并提供资源指标(峰值 RSS 和 CPU)。```sh
cargo bench --bench cli -- run # defaults: sk, 1 M items, query "test"
cargo bench --bench cli -- run sk -n 500000 -q foo # bare name resolved via $PATH
cargo bench --bench cli -- run ./old/sk ./new/sk -r 5 # compare two binaries, 5 runs each
cargo bench --bench cli -- run sk -f input.txt -q search # use an existing file
cargo bench --bench cli -- generate -f testdata.txt -n 2000000 # generate input file and exit
cargo bench --bench cli -- run sk --perf # record perf data (auto-named file)
cargo bench --bench cli -- run sk --strace # record strace data (auto-named file)
cargo bench --bench cli -- run sk -p perf.data # record perf data to perf.data
cargo bench --bench cli -- run sk -j # JSON output
cargo bench --bench cli -- run sk -r 3 -- --tiebreak=index # pass extra flags to sk
二进制名称在使用前会通过 which 解析为绝对路径,因此只要 sk 或 fzf 等裸名称位于 $PATH 中,即可直接使用。
Criterion 基准测试可用于更精确地衡量 skim 的性能。
要运行它们,你需要先使用 cargo bench --bench cli -- -g benches/fixtures/10M.txt -n 10000000 && cargo bench --bench cli -- -g benches/fixtures/1M.txt -n 1000000 生成输入数据,然后运行 cargo bench -j 1。
这些测试将运行几分钟。
| 操作系统 | 包管理器 | 命令 |
|---|
| macOS | Homebrew | brew install sk |
| macOS | MacPorts | sudo port install skim |
| Alpine | apk | apk add skim |
| Arch | pacman | pacman -S skim |
| Fedora | COPR | 见下文 |
| Gentoo | Portage | emerge --ask app-misc/skim |
| Guix | guix | guix install skim |
| Void | XBPS | xbps-install -S skim |
| 按键 | 操作 |
|---|
| Enter | 接受(选择当前项并退出) |
| ESC/Ctrl-G | 中止 |
| Ctrl-P/上箭头 | 光标上移 |
| Ctrl-N/下箭头 | 光标下移 |
| TAB | 切换选择并下移(配合 -m) |
| Shift-TAB | 切换选择并上移(配合 -m) |
| 标记 | 匹配类型 | 描述 |
|---|
text | 模糊匹配 | 匹配 text 的项 |
^music | 前缀精确匹配 | 以 music 开头的项 |
.mp3$ | 后缀精确匹配 | 以 .mp3 结尾的项 |
'wild | 精确匹配(带引号) | 包含 wild 的项 |
!fire | 反向精确匹配 | 不包含 fire 的项 |
!.mp3$ | 反向后缀精确匹配 | 不以 .mp3 结尾的项 |
使用 --split-match 选项时,空格或 | 周围的每个部分将以拆分方式进行匹配:
:),则进行普通匹配rg 管道输入以同时匹配文件名和内容时特别有用。