在bash中显示空列(固定宽度和空格分隔)的列

时间:2017-05-02 09:57:03

标签: bash shell awk

我的日志文件(在txt中)包含以下文字

UNIT       PHYS STATE LOCATION              INFO
TCSM-1098       SE-NH                        -                            
ETPE-5-0   1403 SE-OU              BCSU-1   ACTV FLTY                     
ETIP-6     1402 SE-NH                        -                            

他们被空间界定了...... 我如何获得如下的输出?

UNIT|PHYS|STATE|LOCATION|INFO
TCSM-1098||SE-NH||-                            
ETPE-5-0|1403|SE-OU|BCSU-1|ACTV FLTY                     
ETIP-6|1402|SE-NH||-    

提前感谢

这是我到目前为止所尝试的

cat file.txt | awk 'BEGIN { FS = "[[:space:]][[:space:]]+" } {print $1,$2,$3,$4}' | sed 's/ /|/g'

它产生这样的输出

|UNIT|PHYS|STATE|LOCATION|INFO|
|TCSM-1098|SE-NH|-|
|ETPE-5-0|1403|SE-OU|BCSU-1|ACTV|FLTY
|ETIP-6|1402|SE-NH|-|

该栏目并不像我希望的那样

4 个答案:

答案 0 :(得分:4)

它似乎没有分隔,而是固定宽度格式。

$ perl -ple '
    $_ = join "|", 
        map {s/^\s+|\s+$//g;$_}
        unpack ("a11 a5 a6 a22 a30",$_);
'  <file.txt

如何运作

  • -p switch:循环输入行(默认var:$ _)并打印
  • -l switch:chomp line ending(\ n)并将其添加到输出
  • -e:内联命令

  • 解包函数:获取定义的格式和输入行并返回数组

  • map函数:将块应用于数组的每个元素:正则表达式以删除标题尾随空格
  • join函数:接受分隔符和数组并给出字符串
  • $ _ =:将字符串影响为输出的默认值var

答案 1 :(得分:2)

Perl救援!

perl -wE 'my @lengths;
          $_ = <>;
          push @lengths, length $1 while /(\S+\s*)/g;
          $lengths[-1] = "*";
          my $f;
          say join  "|",
              map s/^\s+|\s+$//gr,
              unpack "A" . join("A", @lengths), $_
          while (!$f++ or $_ = <>);' -- infile

格式不是空白分隔,而是固定宽度。

@lengths数组将填充从输入的第一行获取的列的宽度。最后一列宽度已替换为*,因为其宽度无法从标题中推断出来。

然后,根据用于解析文件的长度创建unpack模板。

$f只是一个标志,可以将模板应用于标题行本身。

答案 2 :(得分:1)

用FIELDWITDHS的GNU awk来处理固定宽度的字段:

awk -v FIELDWIDTHS='11 5 6 22 99' -v OFS='|' '{$1=$1; gsub(/ *\| */,"|"); sub(/ +$/,"")}1' file
UNIT|PHYS|STATE|LOCATION|INFO
TCSM-1098||SE-NH||-
ETPE-5-0|1403|SE-OU|BCSU-1|ACTV FLTY
ETIP-6|1402|SE-NH||-

我认为这是非常明确和不言自明的,但如果您有任何问题,请告诉我。

答案 3 :(得分:0)

手动,在awk

$ awk 'BEGIN{split("11 5 6 23 99", cols); } 
    {s=0; 
     for (i in cols) {
        field = substr($0, s, cols[i]); 
        s += cols[i]; 
        sub(/^ */, "", field);
        sub(/ *$/, "", field); 
        printf "%s|", field;  
     }; 
     printf "\n" } ' file
UNIT|PHYS|STATE|LOCATION|INFO|
TCSM-1098||SE-NH||-|
ETPE-5-0|1403|SE-OU|BCSU-1|ACTV FLTY|
ETIP-6|1402|SE-NH||-|

列的宽度在BEGIN块中设置,然后对于每一行,我们获取所需长度的行的子串。 s计算当前列的起始位置,sub()调用删除前导和尾随空格。这样的代码在每一行上打印一个尾随|,但这可以通过使第一列或最后一列成为特殊情况来解决。

请注意,最后一个字段与输出中的字段不同,很难说明ACTVFLTY之间的分割位置。是固定宽度,还是空间是分隔符?