Linux命令 curl


原文链接: Linux命令 curl

一点黑魔法:Linux 中对纯文本文件的列操作

如果你经常和数据打交道,那么你肯定会经常需要对列进行操作。在 Linux 中,对纯文本文件的列操作有两个十分有用的命令:cutpaste。其中 cut 主要用于从纯文本文件中取出某些列,paste 则可以用于按列合并。

cut 命令

假设有这样一个测试文件 cut.txt

+--------------------------------------+--------------------------------------+
| 1 | 1|2|3|4|5|6|7|8|九|0 |
| 2 | 1|2|3|4|5|6|7|8|九|0 |
| 3 | 1|2|3|4|5|6|7|8|九|0 |
| 4 | 1|2|3|4|5|6|7|8|九|0 |
| 5 | 1|2|3|4|5|6|7|8|九|0 |
| 6 | 1|2|3|4|5|6|7|8|九|0 |
+--------------------------------------+--------------------------------------+

我们将用这个测试文件来做一些实验。

cut 基础与字节模式

前面说过,cut 命令的本职工作就是取出某些列。实际上,更准确地说法,是 cut 命令逐行地处理输入,并从中取出某些列。这里说的「列」有三种模式:

+--------------------------------------+--------------------------------------+
| 1 | -b # 以字节作为标准取出列 |
| 2 | -c # 以字符作为标准取出列 |
| 3 | -f # 以域 (field) 作为标准取出列 |
+--------------------------------------+--------------------------------------+

首先我们看看字节模式。比如我们可以取出每一行的第三个字节中的内容。我们知道,英文字符都是以 ASCII 编码用一个字符保存的。这样,我们预期会输出 6 个 2。我们来看下实际的输出。

+--------------------------------------+--------------------------------------+
| 1 | $ cut -b 3 cut.txt |
| 2 | 2 |
| 3 | 2 |
| 4 | 2 |
| 5 | 2 |
| 6 | 2 |
| 7 | 2 |
+--------------------------------------+--------------------------------------+

完美,完全符合预期!

我们来看一下 cut 命令的样式

+--------------------------------------+--------------------------------------+
| 1 | cut -[b,c,f] |
+--------------------------------------+--------------------------------------+

在刚才的例子中,我们选择了字节模式(-b),并指定了第三列。值得一提的是,cut 命令的列指定风格非常的灵活。

+--------------------------------------+--------------------------------------+
| 1 | 3 # 第三列 |
| 2 | 3,5,8 # 第三列、第五列、第八列 |
| 3 | 3-5,8 # 第三列至第五列、第八列 |
| 4 | -3,8 # 第一列至第三列、第八列 |
| 5 | 1,3- # 第一列、第三列至最后一列 |
+--------------------------------------+--------------------------------------+

字节模式在某些情况会遇到问题。比如,遇到非 ASCII 编码的字符时(特别是多字节字符),就会遇到问题。我们试着看看用 -b 模式输出第 17 列会怎样。

+--------------------------------------+--------------------------------------+
| 1 | $ cut -b 17 cut.txt |
+--------------------------------------+--------------------------------------+

实际上,-b 模式的第 17 列,会输出「九」的第一个字节。具体输出的内容取决于系统使用的编码。如果我们想输出字符「九」就需要使用字符模式了。

字符模式与域模式

-c 是字符模式。为了输出一列汉字「九」,我们可以这样

+--------------------------------------+--------------------------------------+
| 1 | $ cut -c 17 cut.txt |
| 2 | 九 |
| 3 | 九 |
| 4 | 九 |
| 5 | 九 |
| 6 | 九 |
| 7 | 九 |
+--------------------------------------+--------------------------------------+

除了解析列的方式不一样之外,-c-b 完全一样。

类似的,还有域模式。与字节模式以及字符模式最大的不同是,域模式可以指定单个字符作为分隔符,逐行地将文件分成若干列。比如,这里我们可以用 | 作为分隔符,输出第三列至第五列以及第九列。注意,在列模式下,分隔符也会按需输出。

+--------------------------------------+--------------------------------------+
| 1 | $ cut -d '|' -f 3-5,9 cut.txt |
| 2 | 3|4|5|九 |
| 3 | 3|4|5|九 |
| 4 | 3|4|5|九 |
| 5 | 3|4|5|九 |
| 6 | 3|4|5|九 |
| 7 | 3|4|5|九 |
+--------------------------------------+--------------------------------------+

补集

cut 命令还支持 --complement 参数,意思是取补集。比如在我们刚才的例子中,取补集就意味着取出第一列、第二列、第六列至第八列以及第十列。

+--------------------------------------+--------------------------------------+
| 1 | $ cut -d '|' -f 3-5,9 --compleme |
| 2 | nt cut.txt |
| 3 | 1|2|6|7|8|0 |
| 4 | 1|2|6|7|8|0 |
| 5 | 1|2|6|7|8|0 |
| 6 | 1|2|6|7|8|0 |
| 7 | 1|2|6|7|8|0 |
| | 1|2|6|7|8|0 |
+--------------------------------------+--------------------------------------+

使用 --complement 参数,我们可以很容易地从纯文本中删除某一列。比如我们想删除第四列

+--------------------------------------+--------------------------------------+
| 1 | $ cut -d '|' -f 4 --complement c |
| 2 | ut.txt |
| 3 | 1|2|3|5|6|7|8|九|0 |
| 4 | 1|2|3|5|6|7|8|九|0 |
| 5 | 1|2|3|5|6|7|8|九|0 |
| 6 | 1|2|3|5|6|7|8|九|0 |
| 7 | 1|2|3|5|6|7|8|九|0 |
| | 1|2|3|5|6|7|8|九|0 |
+--------------------------------------+--------------------------------------+

轻而易举~

一点黑魔法:处理连续空格分割的情况

cut 在处理连续空格分割列的时候,结果就会变得一团糟。不过,好在我们有 tr 命令。使用 -s 参数,可以逐行地将连续的字符 unique 成单独的一个字符。

+--------------------------------------+--------------------------------------+
| 1 | $ who |
| 2 | Liam :0 2016-11-08 00: |
| 3 | 07 |
| 4 | Liam pts/0 2016-11-08 00: |
| 5 | 23 (:0.0) |
| 6 | Liam pts/1 2016-11-08 00: |
| 7 | 15 (:0.0) |
| 8 | $ who | tr -s ' ' |
| | Liam :0 2016-11-08 00:07 |
| | Liam pts/0 2016-11-08 00:23 (:0. |
| | 0) |
| | Liam pts/1 2016-11-08 00:15 (:0. |
| | 0) |
+--------------------------------------+--------------------------------------+

这样,我们就能轻易地获得各个用户的登录时间了

+--------------------------------------+--------------------------------------+
| 1 | $ who | tr -s ' ' | cut -d ' ' - |
| 2 | f 1,3,4 |
| 3 | Liam 2016-11-08 00:07 |
| 4 | Liam 2016-11-08 00:23 |
| | Liam 2016-11-08 00:15 |
+--------------------------------------+--------------------------------------+

paste 命令

基本用法

相比 cut 命令,paste 命令的用法就简单粗暴许多了。

假设我们有三个文件

+--------------------------------------+--------------------------------------+
| 1 | $ cat paste1.txt | $ cat paste2 |
| 2 | .txt | $ cat paste3.txt |
| 3 | 1 | a |
| 4 | | A |
| | 2 | b |
| | | B |
| | 3 | c |
| | | C |
+--------------------------------------+--------------------------------------+

现在我们用 paste 试试看

+--------------------------------------+--------------------------------------+
| 1 | $ paste paste1.txt paste2.txt |
| 2 | 1 a |
| 3 | 2 b |
| 4 | 3 c |
| 5 | $ paste paste2.txt paste1.txt |
| 6 | a 1 |
| 7 | b 2 |
| 8 | c 3 |
| 9 | $ paste paste2.txt paste1.txt pa |
| 10 | ste3.txt |
| 11 | a 1 A |
| 12 | b 2 B |
| 13 | c 3 C |
| 14 | $ paste paste2.txt paste1.txt pa |
| 15 | ste3.txt | sed -n l |
| 16 | a\t1\tA |
| | b\t2\tB |
| | c\t3\tC |
+--------------------------------------+--------------------------------------+

不难发现,paste 命令支持输入多个文件,并按顺序将他们用制表符粘在一起。如果你想用其他的分隔符将他们粘在一起,也可以像 cut 命令那样使用 -d 参数指定。

+--------------------------------------+--------------------------------------+
| 1 | $ paste -d '|' paste2.txt paste1 |
| 2 | .txt paste3.txt |
| 3 | a|1|A |
| 4 | b|2|B |
| | c|3|C |
+--------------------------------------+--------------------------------------+

一点黑魔法:避免使用临时文件

如果我们需要将几个程序的即时输出(标准输出)按列粘在一起的话,可能不得不将这些输出先写入临时文件当中,然后再调用 paste 命令。不过,也有不用这样麻烦的办法——使用 Bash Process Substituation 来解决这个问题。

简单来说,就是使用 <(command) 来「伪装成一个文件」的样子,作为 paste 命令的输入。比如

+--------------------------------------+--------------------------------------+
| 1 | $ paste -d '|' <(cat paste2.txt) |
| 2 | <(cat paste1.txt) <(cat paste3.txt) |
| 3 | a|1|A |
| 4 | b|2|B |
| | c|3|C |
+--------------------------------------+--------------------------------------+


您的鼓励是我写作最大的动力
俗话说,投资效率是最好的投资。 如果您感觉我的文章质量不错,读后收获很大,预计能为您提高 10% 的工作效率,不妨小额捐助我一下,让我有动力继续写出更多好文章。

#Column #Cut #Linux #Paste

** Linux 相关信息速查表

Shell 变量引用和字符串处理 **

  • 文章目录
  • 站点概览

Liam Huang
Liam Huang

不忘初心,方得始终。

169 日志

8 分类

356 标签

** RSS

Creative Commons

友情链接

Anyi 王穆荣 Kang_Lu 巩朋 亓欣波 果冻想 Grok Jiayu

  1. 1. cut 命令

    1. 1.1. cut 基础与字节模式
    2. 1.2. 字符模式与域模式
    3. 1.3. 补集
    4. 1.4. 一点黑魔法:处理连续空格分割的情况

  2. 2. paste 命令

    1. 2.1. 基本用法
    2. 2.2. 一点黑魔法:避免使用临时文件

© 2013 -- 2017 ** Liam Huang

Hexo 强力驱动

主题 - NexT.Mist    |    您是本站第 位访问者

`