mirror of
https://github.com/LCTT/TranslateProject.git
synced 2025-01-13 22:30:37 +08:00
PRF
This commit is contained in:
parent
f2d70e188b
commit
54a36a3e32
@ -1,6 +1,6 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (lxbwolf)
|
||||
[#]: reviewer: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to remove duplicate lines from files with awk)
|
||||
@ -9,80 +9,73 @@
|
||||
|
||||
怎样使用 awk 删掉文件中重复的行
|
||||
======
|
||||
学习怎样使用 awk 的 `!visited[$0]++` 在不重新排序或改变原排列顺序的前提下删掉重复的行。
|
||||
|
||||
> 学习怎样使用 awk 的 `!visited[$0]++` 在不重新排序或改变原排列顺序的前提下删掉重复的行。
|
||||
|
||||
![Coding on a computer][1]
|
||||
|
||||
假设你有一个文本文件,你需要删掉所有重复的行。
|
||||
|
||||
### 这篇内容篇幅比较长,如果不想深入探讨或时间有限,可以看总结。
|
||||
|
||||
*保持原来的排列顺序*删掉重复行,使用:
|
||||
### TL;DR
|
||||
|
||||
*要保持原来的排列顺序*删掉重复行,使用:
|
||||
|
||||
```
|
||||
`awk '!visited[$0]++' your_file > deduplicated_file`
|
||||
awk '!visited[$0]++' your_file > deduplicated_file
|
||||
```
|
||||
|
||||
### 工作原理
|
||||
|
||||
这个脚本维持一个关联数组,*index 总数*为文件去重后的行数,每个 index 对应的 *value* 为某行出现的次数。对于文件的每一行,如果这行出现的次数为 0,则 value 加 1 *并打印这行*,否则 value 加 1 *不打印这行*。
|
||||
这个脚本维持一个关联数组,索引为文件中去重后的行,每个索引对应的值为该行出现的次数。对于文件的每一行,如果这行出现的次数为 0,则值加 1,并打印这行,否则值加 1,不打印这行。
|
||||
|
||||
我之前不熟悉 **awk**,我想弄清楚这么短小的一个脚本是怎么实现的。我调研了下,下面是调研心得:
|
||||
我之前不熟悉 `awk`,我想弄清楚这么短小的一个脚本是怎么实现的。我调研了下,下面是调研心得:
|
||||
|
||||
* awk “脚本” **!visited[$0]++** 对输入文件的*每一行*都执行
|
||||
* **visited[]** 是一个 [关联数组][2] (又名 [Map][3])的变量。 **awk** 会在第一次执行时初始化它,因此我们不需要初始化。
|
||||
* **$0** 变量的值是当前正在被处理的行的内容
|
||||
* **visited[$0]** 通过与 **$0**(正在被处理的行)相等的 key 访问 map 中的值,即出现次数(我们在下面设置的)
|
||||
* **!** 对表示出现次数的值取反
|
||||
* 在 awk 中,[任意非零的数或任意非空的字符串的值是 true][4]。
|
||||
* [变量默认的初始值为空字符串][5],如果被转换为数字,则为 0.
|
||||
* 这个 awk “脚本” `!visited[$0]++` 对输入文件的*每一行*都执行。
|
||||
* `visited[]` 是一个[关联数组][2](又名[映射][3])类型的变量。`awk` 会在第一次执行时初始化它,因此我们不需要初始化。
|
||||
* `$0` 变量的值是当前正在被处理的行的内容。
|
||||
* `visited[$0]` 通过与 `$0`(正在被处理的行)相等的键来访问该映射中的值,即出现次数(我们在下面设置的)。
|
||||
* `!` 对表示出现次数的值取反:
|
||||
* 在 `awk` 中,[任意非零的数或任意非空的字符串的值是 true][4]。
|
||||
* [变量默认的初始值为空字符串][5],如果被转换为数字,则为 0。
|
||||
* 也就是说:
|
||||
* 如果 **visited[$0]** 的值是一个比 0 大的数,取反后被解析成 **false**。
|
||||
* 如果 **visited[$0]** 的值为等于 0 的数字或空字符串,取反后被解析成 **true** 。
|
||||
* **++** 表示变量(visited[$0])的值加 1.
|
||||
* 如果值为空,**awk** 自动把它转换为 **0**(数字) 后加 1。
|
||||
* **注意:**加 1 操作是在我们取到了变量的值之后执行的。
|
||||
|
||||
|
||||
* 如果 `visited[$0]` 的值是一个比 0 大的数,取反后被解析成 `false`。
|
||||
* 如果 `visited[$0]` 的值为等于 0 的数字或空字符串,取反后被解析成 `true` 。
|
||||
* `++` 表示变量(`visited[$0]`)的值加 1。
|
||||
* 如果该值为空,`awk` 自动把它转换为 `0`(数字) 后加 1。
|
||||
* 注意:加 1 操作是在我们取到了变量的值之后执行的。
|
||||
|
||||
总的来说,整个表达式的意思是:
|
||||
|
||||
* **true** 如果表示出现次数的值为 0 或空字符串
|
||||
* **false** 如果出现的次数大于 0
|
||||
|
||||
|
||||
|
||||
**awk** 由 [_pattern 表达式和一个与之关联的 action_][6] 组成
|
||||
* `true`:如果表示出现次数为 0 或空字符串
|
||||
* `false`:如果出现的次数大于 0
|
||||
|
||||
`awk` 由 [模式或表达式和一个与之关联的动作][6] 组成
|
||||
|
||||
```
|
||||
`<pattern/expression> { <action> }`
|
||||
<模式/表达式> { <动作> }
|
||||
```
|
||||
|
||||
如果匹配到了 pattern,就会执行后面的 action。如果没有 action,**awk** 默认会 **print** 输入。
|
||||
如果匹配到了模式,就会执行后面的动作。如果没有动作,`awk` 默认会打印(`print`)输入。
|
||||
|
||||
> 省略 action 等于 **{print $0}**。
|
||||
|
||||
我们的脚本由一个 **awk** 表达式语句组成,省略了 action。因此这样写:
|
||||
> 省略动作等价于 `{print $0}`。
|
||||
|
||||
我们的脚本由一个 `awk` 表达式语句组成,省略了动作。因此这样写:
|
||||
|
||||
```
|
||||
`awk '!visited[$0]++' your_file > deduplicated_file`
|
||||
awk '!visited[$0]++' your_file > deduplicated_file
|
||||
```
|
||||
|
||||
等于这样写:
|
||||
|
||||
|
||||
```
|
||||
`awk '!visited[$0]++ { print $0 }' your_file > deduplicated_file`
|
||||
awk '!visited[$0]++ { print $0 }' your_file > deduplicated_file
|
||||
```
|
||||
|
||||
对于文件的每一行,如果表达式匹配到了,这行内容被 print 到输出。否则,不执行 action,不打印任何东西。
|
||||
对于文件的每一行,如果表达式匹配到了,这行内容被打印到输出。否则,不执行动作,不打印任何东西。
|
||||
|
||||
### 为什么不用 uniq 命令?
|
||||
|
||||
**uniq** 命令仅能对相邻的行去重。这是一个示例:
|
||||
|
||||
`uniq` 命令仅能对相邻的行去重。这是一个示例:
|
||||
|
||||
```
|
||||
$ cat test.txt
|
||||
@ -100,7 +93,7 @@ C
|
||||
B
|
||||
B
|
||||
A
|
||||
$ uniq < test.txt
|
||||
$ uniq < test.txt
|
||||
A
|
||||
B
|
||||
A
|
||||
@ -113,11 +106,11 @@ A
|
||||
|
||||
#### 使用 sort 命令
|
||||
|
||||
我们也可以用下面的 [**sort**][7] 命令来去除重复的行,但是*行原来的顺序没有被保留*。
|
||||
我们也可以用下面的 [sort][7] 命令来去除重复的行,但是*原来的行顺序没有被保留*。
|
||||
|
||||
|
||||
```
|
||||
`sort -u your_file > sorted_deduplicated_file`
|
||||
sort -u your_file > sorted_deduplicated_file
|
||||
```
|
||||
|
||||
#### 使用 cat + sort + cut
|
||||
@ -126,13 +119,12 @@ A
|
||||
|
||||
|
||||
```
|
||||
`cat -n your_file | sort -uk2 | sort -nk1 | cut -f2-`
|
||||
cat -n your_file | sort -uk2 | sort -nk1 | cut -f2-
|
||||
```
|
||||
|
||||
##### 工作原理
|
||||
|
||||
假设我们有下面一个文件
|
||||
**工作原理**
|
||||
|
||||
假设我们有下面一个文件:
|
||||
|
||||
```
|
||||
abc
|
||||
@ -145,8 +137,7 @@ ghi
|
||||
klm
|
||||
```
|
||||
|
||||
**cat -n test.txt** 在每行前面显示序号。
|
||||
|
||||
`cat -n test.txt` 在每行前面显示序号:
|
||||
|
||||
```
|
||||
1 abc
|
||||
@ -159,8 +150,7 @@ klm
|
||||
8 klm
|
||||
```
|
||||
|
||||
**sort -uk2** 基于第二列(**k2** 选项)进行排序,对于第二列相同的值只保留一次(**u** 选项)。
|
||||
|
||||
`sort -uk2` 基于第二列(`k2` 选项)进行排序,对于第二列相同的值只保留一次(`u` 选项):
|
||||
|
||||
```
|
||||
1 abc
|
||||
@ -170,8 +160,7 @@ klm
|
||||
5 xyz
|
||||
```
|
||||
|
||||
**sort -nk1** 基于第一列排序(**k1** 选项),把列的值作为数字来处理(**-n** 选项)。
|
||||
|
||||
`sort -nk1` 基于第一列排序(`k1` 选项),把列的值作为数字来处理(`-n` 选项):
|
||||
|
||||
```
|
||||
1 abc
|
||||
@ -181,8 +170,7 @@ klm
|
||||
8 klm
|
||||
```
|
||||
|
||||
最后,**cut -f2-** 打印每一行从第二列开始直到最后的内容(**-f2-** 选项:留意 - 后缀,- 表示这行后面的内容都包含在内)。
|
||||
|
||||
最后,`cut -f2-` 从第二列开始打印每一行,直到最后的内容(`-f2-` 选项:留意 `-` 后缀,它表示这行后面的内容都包含在内)。
|
||||
|
||||
```
|
||||
abc
|
||||
@ -196,21 +184,13 @@ klm
|
||||
|
||||
* [GNU awk 用户手册][9]
|
||||
* [awk 中的数组][2]
|
||||
* [Awk—Truth values][4]
|
||||
* [Awk — 真值][4]
|
||||
* [Awk 表达式][5]
|
||||
* [Unix 怎么删除文件中重复的行?][10]
|
||||
* [不用排序去掉重复的行【去重】][11]
|
||||
* [不用排序去掉重复的行(去重)][11]
|
||||
* ['!a[$0]++' 工作原理][12]
|
||||
|
||||
|
||||
|
||||
以上为全文。附上猫照。
|
||||
|
||||
![Duplicate cat][13]
|
||||
|
||||
* * *
|
||||
|
||||
本文首发在 [Lazarus Lazaridis][14] 的 iridakos 博客,遵照 [CC BY-NC 4.0 License][15] ,转载已获得作者授权。
|
||||
以上为全文。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -219,7 +199,7 @@ via: https://opensource.com/article/19/10/remove-duplicate-lines-files-awk
|
||||
作者:[Lazarus Lazaridis][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[lxbwolf](https://github.com/lxbwolf)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user