以最简单的形式,假设我有一个自动生成的文件,名为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/g
645 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
_
' '
这样你就得到了你想要的输出。