4.4 用cut按列切分文件

我们也许不需要按行,而是需要按列切分文件。假设我们有一个文本文件,其中按行包含了学生的报表信息,例如No(学号)、Name(姓名)、Mark(成绩)和Percentage(百分比)。我们需要将学生的姓名提取到另一个文件,或者是需要表中的第n列或其中两列甚至更多列。这则攻略将为你演示如何完成这项任务。

4.4.1 预备知识

cut是一个帮我们将文本按列进行切分的小工具。它也可以指定分隔每列的定界符。在cut的术语中,每列都是一个字段。

4.4.2 实战演练

为了提取第一个字段或列,可以使用下面的语法:

  1. cut -f FIELD_LIST filename

FIELD_LIST是需要显示的列。它由列号组成,彼此之间用逗号分隔。例如:

  1. $ cut -f 2,3 filename

这条命令将显示第2列和第3列。

cut也能够从stdin中读取输入文本。

制表符是字段或列的默认定界符。没有定界符的行也会照原样被打印出来。要避免打印出这种不包含定界符的行,则可以使用cut-s选项。一个cut命令的例子如下:

  1. $ cat student_data.txt
  2. No Name Mark Percent
  3. 1 Sarath 45 90
  4. 2 Alex 49 98
  5. 3 Anu 45 90
  6.  
  7. $ cut -f1 student_data.txt
  8. No
  9. 1
  10. 2
  11. 3

提取多个字段:

  1. $ cut -f2,4 student_data.txt
  2. Name Percent
  3. Sarath 90
  4. Alex 98
  5. Anu 90

要打印多列,需要提供一个由逗号分隔的列号列表作为-f选项的参数。

我们也可以用 --complement选项对提取的字段进行补集运算。假设有多个字段,你希望打印出除第3列之外所有的列,则可以使用:

  1. $ cut -f3 --complement student_data.txt
  2. No Name Percent
  3. 1 Sarath 90
  4. 2 Alex 98
  5. 3 Anu 90

要指定字段的定界符,使用 -d选项:

  1. $ cat delimited_data.txt
  2. No;Name;Mark;Percent
  3. 1;Sarath;45;90
  4. 2;Alex;49;98
  5. 3;Anu;45;90
  6.  
  7. $ cut -f2 -d";" delimited_data.txt
  8. Name
  9. Sarath
  10. Alex
  11. Anu

4.4.3 补充内容

cut命令有一些选项可以将一串字符作为列来显示。让我们来看看这些选项。

指定字段的字符或字节范围

假设我们不依赖定界符,但需要通过将字段定义为一个字符范围(行首记为0)来进行字段提取,这种需求也可以用cut来实现。

表4-4中列出了字符字段范围的记法。

表 4-4

记  法 范  围
N- 从第N个字节,字符或字段到行尾
N-M 从第N个字节,字符或字段到第M个(包括第M个在内)字节、字符或字段
-M 第1个字节,字符或字段到第M个(包括第M个在内)字节、字符或字段

用上面介绍的记法,再结合下列选项将某个范围的字节或字符指定为字段:

  • -b 表示字节;

  • -c 表示字符;

  • -f 表示定义字段。

例如:

  1. $ cat range_fields.txt
  2. abcdefghijklmnopqrstuvwxyz
  3. abcdefghijklmnopqrstuvwxyz
  4. abcdefghijklmnopqrstuvwxyz
  5. abcdefghijklmnopqrstuvwxy

你可以打印第1个到第5个字符:

  1. $ cut -c1-5 range_fields.txt
  2. abcde
  3. abcde
  4. abcde
  5. abcde

打印前2个字符:

  1. $ cut range_fields.txt -c-2
  2. ab
  3. ab
  4. ab
  5. ab

若要用字节作为计数单位,可以将 -c替换成 -b

在使用 -c-f-b时,我们可以指定输出定界符:

  1. --output-delimiter "delimiter string"

当用-b-c提取多个字段时,必须使用 --output-delimiter,否则,你就没法区分不同的字段了。例如:

  1. $ cut range_fields.txt -c1-3,6-9 --output-delimiter ","
  2. abc,fghi
  3. abc,fghi
  4. abc,fghi
  5. abc,fghi