Linux命令 curl
一点黑魔法:Linux 中对纯文本文件的列操作
如果你经常和数据打交道,那么你肯定会经常需要对列进行操作。在 Linux 中,对纯文本文件的列操作有两个十分有用的命令:cut
和 paste
。其中 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
命令的样式
+--------------------------------------+--------------------------------------+ 在刚才的例子中,我们选择了字节模式( +--------------------------------------+--------------------------------------+ 字节模式在某些情况会遇到问题。比如,遇到非 ASCII 编码的字符时(特别是多字节字符),就会遇到问题。我们试着看看用 +--------------------------------------+--------------------------------------+ 实际上, +--------------------------------------+--------------------------------------+ 除了解析列的方式不一样之外, 类似的,还有域模式。与字节模式以及字符模式最大的不同是,域模式可以指定单个字符作为分隔符,逐行地将文件分成若干列。比如,这里我们可以用 +--------------------------------------+--------------------------------------+ +--------------------------------------+--------------------------------------+ 使用 +--------------------------------------+--------------------------------------+ 轻而易举 +--------------------------------------+--------------------------------------+ 这样,我们就能轻易地获得各个用户的登录时间了 +--------------------------------------+--------------------------------------+ 相比 假设我们有三个文件 +--------------------------------------+--------------------------------------+ 现在我们用 +--------------------------------------+--------------------------------------+ 不难发现, +--------------------------------------+--------------------------------------+ 如果我们需要将几个程序的即时输出(标准输出)按列粘在一起的话,可能不得不将这些输出先写入临时文件当中,然后再调用 简单来说,就是使用 +--------------------------------------+--------------------------------------+ ❧ 您的鼓励是我写作最大的动力 不忘初心,方得始终。 友情链接 © 2013 -- 2017 ** 由 Hexo 强力驱动 主题 - NexT.Mist | 您是本站第 位访问者
| 1 | cut -[b,c,f]
+--------------------------------------+--------------------------------------+-b
),并指定了第三列。值得一提的是,cut
命令的列指定风格非常的灵活。
| 1 | 3 # 第三列 |
| 2 | 3,5,8 # 第三列、第五列、第八列 |
| 3 | 3-5,8 # 第三列至第五列、第八列 |
| 4 | -3,8 # 第一列至第三列、第八列 |
| 5 | 1,3- # 第一列、第三列至最后一列 |
+--------------------------------------+--------------------------------------+-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% 的工作效率,不妨小额捐助我一下,让我有动力继续写出更多好文章。
Liam Huang