如何从包含制表符和空格的文本创建统一的列?

如何从包含制表符和空格的文本创建统一的列?

以最简单的形式,假设我有一个自动生成的文件,名为file.txt.出现的内容file.txt如下:

 Source                    Destination                Maximum To  Maximum From Average Total   Average To           Average From
(192.168.1.1)   (192.168.1.2)       202.89 Kbps    0 bps         645 bps 645 bps 0 bps

我尝试了该column命令的多种变体,但均无济于事。我怎样才能使这个输出看起来像这样:

Source         Destination     Maximum To     Maximum From     Average Total     Average To     Average From
(192.168.1.1)  (192.168.1.2)   202.89 Kbps    0 bps            645 bps           645 bps        0 bps

我觉得我应该知道如何做到这一点,但我现在一片空白,到目前为止还没有发现任何可以按预期工作的东西。

编辑:下面的评论和答案sed非常适合我原来的示例(实际上我更喜欢评论中的解决方案,因为它更简单并且不涉及管道到tr)。话虽这么说,这两种解决方案在多行文件上的执行效果完全相同。实际file.txt将包括数百行不同长度的 IPv4 地址。sed到目前为止,两种解决方案都在原始结果上返回了以下结果(并且更准确) file.txt

原始文件.txt:

Source                    Destination                Maximum To  Maximum From Average Total   Average To           Average From
(10.10.10.21)     (192.168.123.122)      18.90 Kbps     0 bps         131 bps 131 bps 0 bps
(10.10.10.22)     (192.168.123.122)       10.88 Kbps     0 bps         23 bps 23 bps 0 bps
(10.10.10.23)     (192.168.123.123)       10.88 Kbps     0 bps         23 bps 23 bps 0 bps
(192.168.123.123) (192.52.168.123)       0 bps          22.84 Kbps    1.17 Kbps 0 bps     1.17 Kbps
(192.168.123.124)  (192.52.168.123)       0 bps          10.87 Kbps    19 bps 0 bps  19 bps

更新了 file.txt(在使用迄今为止建议的解决方案之后):

Source                              Destination        Maximum To  Maximum From  Average Total  Average To  Average From
(10.10.10.21)                       (192.168.123.122)  18.90 Kbps  0 bps         131 bps        131 bps     0 bps
(10.10.10.22)                       (192.168.123.122)  10.88 Kbps  0 bps         23 bps         23 bps      0 bps
(10.10.10.23)                       (192.168.123.123)  10.88 Kbps  0 bps         23 bps         23 bps      0 bps
(192.168.123.123) (192.52.168.123)  0 bps              22.84 Kbps  1.17 Kbps     0 bps          1.17 Kbps
(192.168.123.124)                   (192.52.168.123)   0 bps       10.87 Kbps    19 bps         0 bps       19 bps

是否有更新的解决方案可以解决此偏移警告?

答案1

脚本基于 OP 的示例数据。

sed '
    s/\s\s\+/:/g
    s/\([a-z)]\)\s\([(0-9A]\)/\1:\2/g
    ' file.txt | 
column -s: -t
  • 首先更改容易找到的分隔符(2个或更多\s步):
  • 第二步找到剩余的可能分隔符:
    • 小写字母和数字之间
    • )
    • A
  • 使用列分隔符格式化字符串:

答案2

以下 perl 脚本将输入转换为制表符分隔的字段,依赖于前两个字段各只有一个“单词”而其余字段各有两个“单词”的知识。然后将其输出通过管道输送到column -s $'\t' -t

这是一种相当笨拙和蛮力的方法,但它确实有效。

#! /usr/bin/perl 

use strict;

while(<>) {
    my (@F, @fields, $i);

    @F=split;
    $fields[0] = $F[0] ;
    $fields[1] = $F[1] ;
    for $i (0..4) {
      $fields[$i + 2] = $F[$i*2 + 2] . ' ' . $F[$i*2 + 3];
    }

    print join("\t",@fields),"\n";
}

它的使用方式如下:

$ ./bandwidth.pl bandwidth.txt | column -s $'\t' -t 
Source             Destination        Maximum To  Maximum From  Average Total  Average To  Average From
(10.10.10.21)      (192.168.123.122)  18.90 Kbps  0 bps         131 bps        131 bps     0 bps
(10.10.10.22)      (192.168.123.122)  10.88 Kbps  0 bps         23 bps         23 bps      0 bps
(10.10.10.23)      (192.168.123.123)  10.88 Kbps  0 bps         23 bps         23 bps      0 bps
(192.168.123.123)  (192.52.168.123)   0 bps       22.84 Kbps    1.17 Kbps      0 bps       1.17 Kbps
(192.168.123.124)  (192.52.168.123)   0 bps       10.87 Kbps    19 bps         0 bps       19 bps

顺便说一句,这是一个很好的例子,说明了为什么在被分隔的字段中使用分隔符(例如空格)从来都不是一个好主意。它只会使事情变得比需要的更加困难......并且没有可靠的方法来区分分隔符和字段内容,而不需要预先了解文件内容和结构。

答案3

更新:使用完整原件的副本,在此示例中命名full_original.txt

$ sed 's/\((\)/ \1/g;s/\(Average\)/ \1/g;s/ \([0-9]\)/  \1/g;s/\(\S\) \(\S\)/\1_\2/g' full_original.txt | column -t | tr _ ' '
Source             Destination        Maximum To  Maximum From  Average Total  Average To  Average From
(10.10.10.21)      (192.168.123.122)  18.90 Kbps  0 bps         131 bps        131 bps     0 bps
(10.10.10.22)      (192.168.123.122)  10.88 Kbps  0 bps         23 bps         23 bps      0 bps
(10.10.10.23)      (192.168.123.123)  10.88 Kbps  0 bps         23 bps         23 bps      0 bps
(192.168.123.123)  (192.52.168.123)   0 bps       22.84 Kbps    1.17 Kbps      0 bps       1.17 Kbps
(192.168.123.124)  (192.52.168.123)   0 bps       10.87 Kbps    19 bps         0 bps       19 bps

解释

该解决方案的大部分采用“分而治之”的方法,其中您有多个单独的问题,单独解决它们。最后通过magiccolumn命令组装起来,画龙点睛tr

  • 基本模式是s/searchstring/replacestring/g'g对于贪婪/全局,因此适用于所有匹配而不仅仅是第一个
  • 我们使用分组,因此在搜索部分,可以通过“如果是第一组”、“如果是第二组”等\(somegroup\)重新打印\1\2
  • 分号;允许我们在一个实例中放置多个搜索和替换命令sed,比管道更有效,从而运行多个 sed,例如sed command | sed command | sed command ....
  • s/\((\)/ \1/g处理...123) (19...将两个括号括起来的 ip 值彼此推开一个空格以上,以避免 OP 发现的偏移问题。它通过匹配任何左括号(并添加空格前缀来实现此目的,使其变为space+(
  • s/\(Average\)/ \1/g是处理如何没有特殊分隔的部分Maximum From Average Total,使得以后的查找和替换变得困难,所以最初我们在每次出现之前添加一个额外的空格Average
  • s/ \([0-9]\)/ \1/g645 bps 645 bps 0 bps通过在任何出现的 之前添加space+number空格来分隔原始文本中的字段值,这样它就变成space+space+number, 再次帮助后面的 sed 命令区分它们
  • 最后一个 sed 命令s/\(\S\) \(\S\)/\1_\2/g是一种解决方法,它进行搜索non-space+space+non-space并通过分组进行更改,以便将空格变成下划线。这 Maximum To为我们稍后column使用的命令保留在一起,所以它变成Maximum_To
  • | column -t将其通过管道传递给column命令,默认情况下,该命令man column表示:By default, the column command will merge multiple adjacent delimiters into a single delimiter when using the -t option因此它将文本之间的可变空格处理为单个分隔符。
  • 列还执行重新格式化以使文本对齐
  • 最后撤消使用命令| tr _ ' '将空格转换为下划线 ( ) 的解决方法,将所有, 转换回空格。_tr_' '

这样你就得到了你想要的输出。

相关内容