sd/README_zh-CN.md
2024-05-06 11:58:24 +08:00

184 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# sd - `搜索`与`替换`
`sd` 是一个直观的查找与替换命令行工具。
## 宣传
为什么要使用它而不是现有的任何工具?
*无痛的正则表达式*   `sd` 使用您已经熟悉的来自 JavaScript 和 Python 的正则表达式语法。不用再去处理 `sed``awk` 的怪癖 - 立即提高生产力。
*字符串文字模式*   非正则表达式的查找和替换。不再需要反斜杠或记住哪些字符是特殊的并且需要转义。
*易读易写*   查找和替换表达式被拆分开来,这样更容易阅读和编写。不再需要处理未闭合和转义的斜杠。
*智能、常识性的默认设置*   默认设置遵循常识,专为典型的日常使用而定制。
## 与 sed 相比
虽然 sed 可以做更多的事情,但 sd 专注于做一件事情,并且做得很好。以下是一些精选的例子,展示了 sd 的优势所在。
替换所有出现的内容的更简单语法:
- sd: `sd before after`
- sed: `sed s/before/after/g`
将换行符替换为逗号:
- sd: `sd '\n' ','`
- sed: `sed ':a;N;$!ba;s/\n/,/g'`
从包含斜杠的字符串中提取内容:
- sd: `echo "sample with /path/" | sd '.*(/.*/)' '$1'`
- sed: `echo "sample with /path/" | sed -E 's/.*(\\/.*\\/)/\1/g'`
使用 sed你可以使用不同的分隔符来改善但仍然有些混乱
`echo "sample with /path/" | sed -E 's|.*(/.*/)|\1|g'`
原地修改文件:
- sd: `sd before after file.txt`
- sed: `sed -i -e 's/before/after/g' file.txt`
在使用 sed 时,需要记住使用 `-e`,否则某些平台会将下一个参数视为备份后缀。
## 基准测试
**在大约 1.5GB 大小的 JSON 文件上进行简单的替换**
```sh
hyperfine --warmup 3 --export-markdown out.md \
'sed -E "s/\"/'"'"'/g" *.json > /dev/null' \
'sed "s/\"/'"'"'/g" *.json > /dev/null' \
'sd "\"" "'"'"'" *.json > /dev/null'
```
| 命令 | 平均 [s] | 最低…最高 [s] |
|:---|---:|---:|
| `sed -E "s/\"/'/g" *.json > /dev/null` | 2.338 ± 0.008 | 2.332…2.358 |
| `sed "s/\"/'/g" *.json > /dev/null` | 2.365 ± 0.009 | 2.351…2.378 |
| `sd "\"" "'" *.json > /dev/null` | **0.997 ± 0.006** | 0.987…1.007 |
结果:速度提高了大约 2.35 倍
**对一个约 55M 大小的 JSON 文件进行正则表达式替换**:
```sh
hyperfine --warmup 3 --export-markdown out.md \
'sed -E "s:(\w+):\1\1:g" dump.json > /dev/null' \
'sed "s:\(\w\+\):\1\1:g" dump.json > /dev/null' \
'sd "(\w+)" "$1$1" dump.json > /dev/null'
```
| 命令 | 平均 [s] | 最低…最高 [s] |
|:---|---:|---:|
| `sed -E "s:(\w+):\1\1:g" dump.json > /dev/null` | 11.315 ± 0.215 | 11.102…11.725 |
| `sed "s:\(\w\+\):\1\1:g" dump.json > /dev/null` | 11.239 ± 0.208 | 11.057…11.762 |
| `sd "(\w+)" "$1$1" dump.json > /dev/null` | **0.942 ± 0.004** | 0.936…0.951 |
结果:速度提高了大约 11.93 倍
## 安装
通过 [`cargo`](https://doc.rust-lang.org/cargo/getting-started/installation.html) 使用 `cargo install sd` 命令安装,或通过各种包管理器安装。
[![Packaging status](https://repology.org/badge/vertical-allrepos/sd-find-replace.svg?exclude_unsupported=1)](https://repology.org/project/sd-find-replace/versions)
## 快速指南
1. **字符串文字**模式。默认情况下,表达式被视为正则表达式。使用 `-F``--fixed-strings` 可以禁用正则表达式。
```sh
> echo 'lots((([]))) of special chars' | sd -s '((([])))' ''
lots of special chars
```
2. **基本正则表达式的使用** - 让我们去掉一些末尾的空白符
```sh
> echo 'lorem ipsum 23 ' | sd '\s+$' ''
lorem ipsum 23
```
3. **捕获组**
索引捕获组:
```sh
> echo 'cargo +nightly watch' | sd '(\w+)\s+\+(\w+)\s+(\w+)' 'cmd: $1, channel: $2, subcmd: $3'
cmd: cargo, channel: nightly, subcmd: watch
```
命名捕获组:
```sh
> echo "123.45" | sd '(?P<dollars>\d+)\.(?P<cents>\d+)' '$dollars dollars and $cents cents'
123 dollars and 45 cents
```
在不太可能出现歧义的情况下,通过使用 `${var}` 而不是 `$var` 来解决。这里有一个例子:
```sh
> echo '123.45' | sd '(?P<dollars>\d+)\.(?P<cents>\d+)' '$dollars_dollars and $cents_cents'
and
> echo '123.45' | sd '(?P<dollars>\d+)\.(?P<cents>\d+)' '${dollars}_dollars and ${cents}_cents'
123_dollars and 45_cents
```
4. **在文件中查找并替换**
```sh
> sd 'window.fetch' 'fetch' http.js
```
就是这样,文件将直接在原地修改。
预览更改:
```sh
> sd -p 'window.fetch' 'fetch' http.js
```
5. **在整个项目中查找并替换**
这个例子使用了 [fd](https://github.com/sharkdp/fd)。
好的 Unix 哲学来拯救我们了。
```sh
fd --type file --exec sd 'from "react"' 'from "preact"'
```
同理,但带有备份(考虑版本控制)。
```bash
fd --type file --exec cp {} {}.bk \; --exec sd 'from "react"' 'from "preact"'
```
### 极端情况
sd 会将以 `-` 开头的每个参数解释为(可能是未知的)标志。
尊重常见的惯例,使用 `--` 来表示标志的结束:
```bash
$ echo "./hello foo" | sd "foo" "-w"
error: Found argument '-w' which wasn't expected, or isn't valid in this context
USAGE:
sd [OPTIONS] <find> <replace-with> [files]...
For more information try --help
$ echo "./hello foo" | sd "foo" -- "-w"
./hello -w
$ echo "./hello --foo" | sd -- "--foo" "-w"
./hello -w
```
### 转义特殊字符
要转义 `$` 字符,需使用 `$$`
```bash
echo "foo" | sd 'foo' '$$bar'
$bar
```