如何提取/更改数据分隔为字段的文本文件中的行?

如何提取/更改数据分隔为字段的文本文件中的行?

如何从命令行操作基于字段的数据?例如

  • 如何只打印第 N 个字段为 的行foo
  • 如何只打印第 N 个字段不是 的行foo
  • 如何只打印第 N 个字段匹配的行foo
  • 如何将字段 N 更改为foo

是否有一个标准方法或工具集可以帮助在 *nix 系统上操作基于现场的数据?

答案1

处理字段时可以使用两种基本方法:i)使用理解字段的工具; ii) 使用正则表达式。在两者中,前者通常更强大且更简单。

*nix 上的许多常用工具要么明确设计用于处理字段,要么具有巧妙的技巧来促进它。

1. 使用理解字段的工具

1.1 awk

这里的经典工具是awk.它将自动将每个输入行拆分为字段(默认情况下字段分隔符为空格,但可以使用标志进行更改-F),然后这些字段可用于awk脚本,如下所示$nn是字段编号。第一个字段是$1,第二个字段$2等等。

  • 打印第三个字段为 的行foo

    awk '$3=="foo"' file
    

    将分隔符更改为:

    awk -F":" '$3=="foo"' file
    

    默认操作awk是打印。因此上面的命令将打印第三个字段为 的所有行foo。使用时-F,您可以设置任意字段分隔符,甚至可以使用正则表达式。

  • 如何只打印第三个字段不是的行foo

    awk '$3!="foo"' file
    
  • 如何只打印第三个字段匹配的行foo

    如果您只是查找与模式匹配的字段(例如foomatches foobar),请使用~而不是==

    awk '$3~/foo/' file
    
  • 如何仅打印第三个字段不匹配的行foo

    awk '$3!~/foo/' file
    
  • 如何将第三个字段更改为foo

    awk '$3="foo"' file
    

1.2 珀尔

另一种选择是perl单行。与 awk 一样,Perl 是一种功能齐全的脚本语言,但也可以作为命令行程序运行,以脚本作为输入。它的行为是通过命令行开关修改的,其中与这个问题最相关的是:

  • -eperl:应该运行的脚本;
  • -n:逐行读取输入文件;
  • -p:应用 ; 给出的脚本后打印每个输入行-e
  • -lprint:从每个输入行中删除尾随换行符,并为每个调用添加一个换行符;
  • -a:awk-模式,将每个输入行拆分到数组中@F
  • -F: 的字段分隔符-a

一个重要的区别awkperl's -aswitch 将文件分割成一个数组。在 Perl 中,数组从 0 开始,而不是 1。这意味着第二个字段实际上是$F[1]而不是$F[2]。考虑到所有这些,perl上面的等价物是:

  • 打印第三个字段为 的行foo

    perl -ane 'print if $F[2] eq "foo"' file
    

    将分隔符更改为:

    perl -F":" -ane 'print if $F[2] eq "foo"' file
    

    与 不同的是awkperl不能使用正则表达式作为字段分隔符。它们必须是特定的字符或字符串。

  • 如何只打印第三个字段不是的行foo

    perl -ane 'print unless $F[2] eq "foo"' file
    
  • 如何只打印第三个字段匹配的行foo

    perl -ane 'print if $F[2]=~/foo/' file
    
  • 如何仅打印第三个字段不匹配的行foo

    perl -lane 'print unless $F[2]=~/foo/' file
    
  • 如何将第三个字段更改为foo

    这在 Perl 中有点麻烦。通常的方法是更改​​数组中的值@F,然后打印数组。对于简单的空格分隔文件,这很容易:

    perl -lane '$F[2]="foo"; print "@F"' file
    

    使用不同的分隔符,您将需要join数组。否则,它将以空格分隔打印:

    perl -F: -lane '$F[2]="foo"; print join ":",@F' file
    

2. 使用正则表达式

这里的想法是使用正则表达式(简称“regex”)来定义目标字符串在行中的位置。例如,在字段由 分隔的文件中:,我们可以通过匹配第一个字段(第一个字段)之前的所有内容:,然后查找第二个字段来找到第二个字段:

^[^:]*:[^:]*:

这个正则表达式的意思是:

  • ^:行的开头;
  • [^]:否定的字符类。[^:]意思是“除了:”之外的任何事情;
  • *: 0 个或多个先前模式;
  • ::字面意思:

总的来说,这意味着第一个[^:]*是第一个字段,第二个是第二个字段。显然,如果您正在寻找第 14 个字段,这不是很实用,但它对于更简单的事情很有用。那么,我们如何实现它来操纵我们的数据呢?有多种工具可以做到这一点;在这些示例中,我将使用,sed但您可以使用awk,perl或做非常类似的事情python

  • 如何仅打印第二个字段为 的行foo

    sed -n '/^[^:]*:foo:/p' file
    

    抑制-n正常输出,/regex/p意思是“打印正则表达式匹配的任何行。

  • 如何只打印第二个字段不是的行foo

    sed '/^[^:]*:foo:/d' file
    

    与上述逻辑相反。这里,/regex/d意思是“删除正则表达式匹配的任何行。

  • 如何仅打印第二个字段匹配的行foo

    sed -n '/^[^:]*:[^:]*foo/p' file
    
  • 如何仅打印第二个字段不匹配的行foo

    sed '/^[^:]*:[^:]*foo/d' file
    
  • 如何将第二个字段更改为foo

    sed 's/\([^:]*:\)[^:]*/\1foo/' file 
    

    或者,由于sed替换可以通过使用简单的数字标志重复来直接解决模式的出现:

    sed 's/[^:]*/foo/2' file
    

相关内容