47 个版本
0.10.1 | 2024年6月21日 |
---|---|
0.9.2 | 2023年4月11日 |
0.9.1 | 2023年1月26日 |
0.7.5 | 2022年6月7日 |
0.5.4 | 2021年7月17日 |
#77 在 文本处理
30 每月下载量
130KB
2.5K SLoC
🪓 hck
hck
是 hack
的简称,是 cut
的一个更粗糙的形式。
一个接近直接替换 cut 的工具,可以使用正则表达式分隔符而不是固定字符串。此外,该工具允许使用与 cut 相同的列选择语法指定输出列的顺序(以下示例中说明)。
hck
的任何单一功能都不会使其在 awk
、cut
、xsv
或其他此类工具中脱颖而出。其中 hck
突出的是使常见的事情变得简单,例如重新排序输出字段或根据奇怪的分隔符拆分记录。它旨在在探索数据集时简单易用。将其视为位于 cut
和 awk
之间的一个缺口。
hck
在 MIT 或 UNLICENSE 下双许可。
功能
- 输出列的重新排序!例如,如果您使用
-f4,2,8
,输出列将按顺序出现4
、2
、8
- 分隔符被视为正则表达式,即您可以在不需要额外管道到
tr
的情况下分割多个空格! - 指定输出分隔符
- 使用
-F
选项通过头字符串字面量选择列,或通过设置-r
标志使用正则表达式 - 如果文件扩展名可识别并且存在本地二进制文件以执行解压缩,则输入文件将自动解压缩(类似于 ripgrep)。请参阅 解压缩。
- 输出可以使用来自
gzp
的多线程压缩器进行 gzip 压缩,使用-Z
标志- 这种压缩后的输出是 BGZF 格式,可以使用
tabix
进行索引和查询
- 这种压缩后的输出是 BGZF 格式,可以使用
- 可以通过索引或标题排除字段。
- 速度
非目标
hck
并不旨在成为一个完整的 CSV / TSV 解析器,例如xsv
,它将遵守引号规则。它的行为类似于cut
,即无论分隔符在行中的位置如何,都会分割行。- 分隔符不能包含换行符...嗯,它们可以,但永远不会被看到。
hck
总是逐行工具,其中换行符是标准的\n
\r\n
。
安装
- Homebrew / Linuxbrew
brew tap sstadick/hck
brew install hck
- Conda
# Note, this version lags by about a day
conda install -c conda-forge hck
- MacPorts
# Note, version may lag behind latest
sudo port selfupdate
sudo port install hck
- Debian (Ubuntu)
curl -LO https://github.com/sstadick/hck/releases/download/<latest>/hck-linux-amd64.deb
sudo dpkg -i hck-linux-amd64.deb
* 使用配置文件引导优化构建
- 使用 Rust 工具链
export RUSTFLAGS='-C target-cpu=native'
cargo install hck
-
从 发布页面 (二进制文件已使用配置文件引导优化构建)
-
或者,如果您想要尽可能快的构建,同时利用配置文件引导优化和原生 CPU 功能
# Assumes you are on stable rust
# NOTE: this won't work on windows, see CI for linked issue
cargo install just
git clone https://github.com/sstadick/hck
cd hck
just install-native
- 欢迎并鼓励提交为添加更多包装选项和构建类型的 PR!我特别欢迎为 Windows 家族的包管理器/确保一切对 Windows 友好的 PR。
包装状态
示例
使用字符串字面量分割
❯ hck -Ld' ' -f1-3,5- ./README.md | head -n4
# 🪓 hck
<p align="center">
<a src="https://github.com/sstadick/hck/workflows/Check/badge.svg" alt="Build Status"></a>
使用正则表达式分隔符分割
# note, '\s+' is the default
❯ ps aux | hck -f1-3,5- | head -n4
USER PID %CPU VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 169452 13472 ? Ss Jun21 0:19 /sbin/init splash
root 2 0.0 0 0 ? S Jun21 0:00 [kthreadd]
root 3 0.0 0 0 ? I< Jun21 0:00 [rcu_gp]
重新排序输出列
❯ ps aux | hck -f2,1,3- | head -n4
PID USER %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
1 root 0.0 0.0 169452 13472 ? Ss Jun21 0:19 /sbin/init splash
2 root 0.0 0.0 0 0 ? S Jun21 0:00 [kthreadd]
3 root 0.0 0.0 0 0 ? I< Jun21 0:00 [rcu_gp]
排除输出列
❯ ps aux | hck -e3,5 | head -n4
USER PID %MEM RSS TTY STAT START TIME COMMAND
root 1 0.0 14408 ? Ss Jun21 0:27 /sbin/init splash
root 2 0.0 0 ? S Jun21 0:01 [kthreadd]
root 3 0.0 0 ? I< Jun21 0:00 [rcu_gp]
使用标题正则表达式排除输出列
❯ ps aux | hck -r -E "CPU" -E "^ST.*" | head -n4
USER PID %MEM VSZ RSS TTY TIME COMMAND
root 1 0.0 170224 14408 ? 0:27 /sbin/init splash
root 2 0.0 0 0 ? 0:01 [kthreadd]
root 3 0.0 0 0 ? 0:00 [rcu_gp]
更改输出记录分隔符
❯ ps aux | hck -D'___' -f2,1,3 | head -n4
PID___USER___%CPU
1___root___0.0
2___root___0.0
3___root___0.0
使用正则表达式选择列
# Note the order match the order of the -F args
ps aux | hck -r -F '^ST.*' -F '^USER$' | head -n4
STAT START USER
Ss Jun21 root
S Jun21 root
I< Jun21 root
自动解压缩
❯ gzip ./README.md
❯ hck -Ld' ' -f1-3,5- -z ./README.md.gz | head -n4
# 🪓 hck
<p align="center">
<a src="https://github.com/sstadick/hck/workflows/Check/badge.svg" alt="Build Status"></a>
根据多个字符分割
# with string literal
❯ printf 'this$;$is$;$a$;$test\na$;$b$;$3$;$four\n' > test.txt
❯ hck -Ld'$;$' -f3,4 ./test.txt
a test
3 four
# with an interesting regex
❯ printf 'this123__is456--a789-test\na129_-b849-_3109_-four\n' > test.txt
❯ hck -d'\d{3}[-_]+' -f3,4 ./test.txt
a test
3 four
按索引和标题分割
首先需要解释一下。基本上,按索引和标题选择各自有自己的“顺序”,然后合并这些顺序,例如
❯ printf 'a,b,c,d,e\n1,2,3,4,5\n' | hck -d, -D: -f3 -F 'b' -F 'a'
b:c:a
2:3:1
在按索引的组中,我们指定第 3 列在输出位置 0。在按标题的组中,我们指定列 b
在位置 0。按索引和标题的选择被合并在一起,在合并时,如果有两个输出被指定为在相同的输出位置,它们将按输入顺序输出(输入意味着输入数据中列的顺序)。
这可能会导致意外的结果,例如以下示例中,与上面的示例相比,现在 a
在输出中排在第一位。
❯ printf 'a,b,c,d,e\n1,2,3,4,5\n' | hck -d, -D: -f3 -F 'a'
a:c
1:3
总结:当需要特定的输出顺序且正在混合使用按索引和按标题的字段选择时,请小心。
基准测试
这一组基准测试只是旨在表明 hck
与其他工具处于同一水平。这些旨在捕捉工具的真实世界使用情况,因此在 gcut
的多空格分隔符基准测试中,例如,我们使用 tr
将空格序列转换为单个空格,然后通过管道传递到 gcut
。
注意 这不是权威的基准测试集,只是旨在给出不同方式完成相同任务性能的相对感。
硬件
Ubuntu 20 AMD Ryzen 9 3950X 16 核处理器,配备 64 GB DDR4 内存和 1TB NVMe 硬盘
数据
使用 all_train.csv 数据。
这是一个包含 700 万行的 CSV 数据集。我们使用逗号作为分隔符进行测试,然后也使用 \s\s\s
作为分隔符。
欢迎对使用更多工具或改进(但仍然现实)的命令的基准进行PR。
工具
cut
:
mawk
:
xsv
:
- https://github.com/BurntSushi/xsv
- v0.13.0(本地编译并优化)
tsv-utils
:
- https://github.com/eBay/tsv-utils
- v2.2.0(ldc2,本地编译并优化)
choose
:
- https://github.com/theryangeary/choose
- v1.3.2(本地编译并优化)
单字符分隔符基准
命令 | 平均值 [s] | 最小值 [s] | 最大值 [s] | 相对值 |
---|---|---|---|---|
hck-Ld, -f1,8,19 ./hyper_data.txt> /dev/null |
1.198 ± 0.015 | 1.185 | 1.215 | 1.00 |
hck-Ld, -f1,8,19 --no-mmap./hyper_data.txt> /dev/null |
1.349 ± 0.029 | 1.320 | 1.389 | 1.13 ± 0.03 |
hck-d, -f1,8,19 ./hyper_data.txt> /dev/null |
1.649 ± 0.023 | 1.624 | 1.673 | 1.38 ± 0.03 |
hck-d, -f1,8,19 --no-mmap./hyper_data.txt> /dev/null |
1.869 ± 0.019 | 1.842 | 1.894 | 1.56 ± 0.02 |
tsv-select-d, -f1,8,19 ./hyper_data.txt> /dev/null |
1.702 ± 0.021 | 1.687 | 1.734 | 1.42 ± 0.02 |
choose-f, -i./hyper_data.txt0 7 18 > /dev/null |
4.285 ± 0.092 | 4.214 | 4.428 | 3.58 ± 0.09 |
xsv select-d, 1,8,19 ./hyper_data.txt> /dev/null |
5.693 ± 0.042 | 5.635 | 5.745 | 4.75 ± 0.07 |
awk-F, '{print$1, $8, $19}' ./hyper_data.txt> /dev/null |
4.993 ± 0.029 | 4.959 | 5.030 | 4.17 ± 0.06 |
cut-d, -f1,8,19 ./hyper_data.txt> /dev/null |
7.541 ± 1.250 | 6.827 | 9.769 | 6.30 ± 1.05 |
多字符分隔符基准
命令 | 平均值 [s] | 最小值 [s] | 最大值 [s] | 相对值 |
---|---|---|---|---|
hck-Ld' ' -f1,8,19 ./hyper_data_multichar.txt> /dev/null |
1.718 ± 0.003 | 1.715 | 1.722 | 1.00 |
hck-Ld' ' -f1,8,19 --no-mmap./hyper_data_multichar.txt> /dev/null |
2.191 ± 0.072 | 2.135 | 2.291 | 1.28 ± 0.04 |
hck-d' ' -f1,8,19 ./hyper_data_multichar.txt> /dev/null |
2.180 ± 0.029 | 2.135 | 2.208 | 1.27 ± 0.02 |
hck-d' ' --no-mmap-f1,8,19 ./hyper_data_multichar.txt> /dev/null |
2.542 ± 0.014 | 2.529 | 2.565 | 1.48 ± 0.01 |
hck-d'[[:空格:]]+' -f1,8,19 ./hyper_data_multichar.txt> /dev/null |
8.597 ± 0.023 | 8.575 | 8.631 | 5.00 ± 0.02 |
hck-d'[[:空格:]]+' --no-mmap-f1,8,19 ./hyper_data_multichar.txt> /dev/null |
8.890 ± 0.013 | 8.871 | 8.903 | 5.17 ± 0.01 |
hck-d'\s+' -f1,8,19 ./hyper_data_multichar.txt> /dev/null |
10.014 ± 0.247 | 9.844 | 10.449 | 5.83 ± 0.14 |
hck-d'\s+' -f1,8,19 --no-mmap./hyper_data_multichar.txt> /dev/null |
10.173 ± 0.035 | 10.111 | 10.193 | 5.92 ± 0.02 |
choose-f' ' -i./hyper_data_multichar.txt0 7 18 > /dev/null |
6.537 ± 0.148 | 6.452 | 6.799 | 3.80 ± 0.09 |
choose-f'[[:空格:]]' -i./hyper_data_multichar.txt0 7 18 > /dev/null |
10.656 ± 0.219 | 10.484 | 10.920 | 6.20 ± 0.13 |
choose-f'\s' -i./hyper_data_multichar.txt0 7 18 > /dev/null |
37.238 ± 0.153 | 37.007 | 37.383 | 21.67 ± 0.10 |
awk-F' ' '{print$1, $8 $19}' ./hyper_data_multichar.txt> /dev/null |
6.673 ± 0.064 | 6.595 | 6.734 | 3.88 ± 0.04 |
awk-F' ' '{print$1, $8, $19}' ./hyper_data_multichar.txt> /dev/null |
5.947 ± 0.098 | 5.896 | 6.121 | 3.46 ± 0.06 |
awk-F'[:空格:]+' '{print$1, $8, $19}' ./hyper_data_multichar.txt> /dev/null |
11.080 ± 0.215 | 10.881 | 11.376 | 6.45 ± 0.13 |
< ./hyper_data_multichar.txt tr-s' ' |cut-d' ' -f1,8,19 > /dev/null |
7.471 ± 0.066 | 7.397 | 7.561 | 4.35 ± 0.04 |
< ./hyper_data_multichar.txt tr-s' ' |xsv select-d' ' 1,8,19 --no-headers> /dev/null |
6.172 ± 0.068 | 6.071 | 6.235 | 3.59 ± 0.04 |
< ./hyper_data_multichar.txt tr-s' ' |hck-Ld' ' -f1,8,19 > /dev/null |
6.171 ± 0.112 | 5.975 | 6.243 | 3.59 ± 0.07 |
< ./hyper_data_multichar.txt tr-s' ' |tsv-select-d' ' -f1,8,19 > /dev/null |
6.202 ± 0.130 | 5.984 | 6.290 | 3.61 ± 0.08 |
解压缩
以下表格显示了在指定-z
选项时尝试解压缩文件所使用的文件扩展名/二进制对
扩展名 | 二进制 | 类型 |
---|---|---|
*.gz |
本地 | gzip |
*.tgz |
gzip-d-c |
gzip |
*.bz2 |
bzip2-d-c |
bzip2 |
*.tbz2 |
bzip2-d-c |
bzip2 |
*.xz |
xz-d-c |
xz |
*.txz |
xz-d-c |
xz |
*.lz4 |
lz4-d-c |
lz4 |
*.lzma |
xz--格式=lzma-d-c |
lzma |
*.br |
brotli-d-c |
brotli |
*.zst |
zstd-d-c |
zstd |
*.zstd |
zstd-q-d-c |
zstd |
*.Z |
uncompress-c |
uncompress |
当发现具有上述扩展名之一的文件时,hck
将打开一个子进程运行上述解压缩工具,并从该工具的输出中读取。如果找不到二进制文件,则hck
将尝试按原样读取压缩文件。有关源代码,请参阅grep_cli
。最终目标是添加类似于ripgrep的预处理程序。对于给定类型有多个二进制文件的情况,它们将按照上述顺序尝试。
基于配置文件优化
有关如何使用优化构建此工具的说明,请参阅pgo*.sh
脚本。要使此功能正常工作,您需要通过rustup component add llvm-tools-preview
安装 llvm 工具。使用 PGO 建模似乎可以在平台和代码路径上提高性能5-30%。例如,在mac os上似乎有更大的影响,并且在正则表达式代码路径上也似乎有更大的影响。
待办事项
- 在写入文件时添加输出压缩检测
- 不要为每个新文件重新解析字段/头信息
- 找出如何更好地重用/共享一个vec
- 支持从末尾进行索引(尽管可能性不大)
- 以某种方式内嵌grep/过滤功能(这不会以牺牲
hck
的主要功能为代价) - 将测试从main移动到core
- 添加更多测试
- 根据这里描述的进行并行解析器的实验 此处 考虑到我们不在乎转义引号等问题,这应该是可行的。
更多包和构建
https://github.com/sharkdp/bat/blob/master/.github/workflows/CICD.yml
参考文献
依赖项
~9–19MB
~211K SLoC