如何对齐文本文件中的列

如何对齐文本文件中的列

在 Linux 上使用 bash,如何处理文本文件,以便在特定列之前插入空格,以便该列在输出中对齐?例如:

输入

1653455 ASDFASDF22 bla bla bla asd xmv ASDFASDF22 AA
1944444 ASDFASDF22 klasdfmxvl yxklc erisa ask xdk asdm ase ASDFASDF22 BB
1984945 ASDFASDF22 jklyck aklsdfl asfjasl asdkkcii wdkkkxd aslasl wqe ASDFASDF22 BB

输出

1653455 ASDFASDF22 bla bla bla asd xmv                                ASDFASDF22 AA
1944444 ASDFASDF22 klasdfmxvl yxklc erisa ask xdk asdm ase            ASDFASDF22 BB
1984945 ASDFASDF22 jklyck aklsdfl asfjasl asdkkcii wdkkkxd aslasl wqe ASDFASDF22 BB

两个ASDFASDF22s 之间的列必须少于 50 个字符,否则应被截断。

答案1

一种解决方案使用perl

内容脚本.pl:

use warnings;
use strict;

## Acept one argumnet, the input file.
@ARGV == 1 or die qq[Usage: perl $0 input-file\n];

while ( <> ) {
        ## Remove last '\n' char.
        chomp;

        ## Split line with string 'ASDFASDF22'
        my @f = split /(ASDFASDF22)/;

        ## Print line but print first 49 chars plus a space of the special string.
        printf qq[%s%-50s%s\n],
                join( qq[], @f[0,1] ),
                substr( $f[2], 0, 49 ) . qq[ ],
                join( qq[], @f[3..$#f] );
}

执行脚本:

perl script.pl infile

并输出:

1653455 ASDFASDF22 bla bla bla asd xmv                              ASDFASDF22 AA
1944444 ASDFASDF22 klasdfmxvl yxklc erisa ask xdk asdm ase          ASDFASDF22 BB
1984945 ASDFASDF22 jklyck aklsdfl asfjasl asdkkcii wdkkkxd aslasl w ASDFASDF22 BB

答案2

使用 bash 的数组

while read -r -a words; do
    prefix="${words[0]} ${words[1]}"
    idx=${#words[*]}
    suffix="${words[$((idx-2))]} ${words[$((idx-1))]}"
    unset words[0] words[1] words[$((idx-2))] words[$((idx-1))]
    middle="${words[*]}"
    printf "%s %-50s %s\n" "$prefix" "${middle:0:50}" "$suffix"
done < filename

答案3

我在需要列化的文本文件上尝试了 @Birei 的脚本,但它失败了,因为该文件包含一些与给定分隔符不匹配的行(并且不需要列化)。因此,由于我对 perl 的了解有限,我添加了对数组大小的简单检查,以避免处理不匹配的行。我将在这里发布基本代码,以防其他人需要此更改。

use warnings;
use strict;

## Acept one argumnet, the input file.
@ARGV == 1 or die qq[Usage: perl $0 input-file\n];

while ( <> ) {
    ## Remove last '\n' char.
    chomp;

    ## Split line with string 'ASDFASDF22'
    my @f = split /(ASDFASDF22)/;

    my $f = @f;
    # check array size to avoid errors on non-matching lines
    if ($f > 1)
    {
        ## Print line but print first 49 chars plus a space of the special string.
        printf qq[%s%-50s%s\n],
                join( qq[], @f[0,1] ),
                substr( $f[2], 0, 49 ) . qq[ ],
                join( qq[], @f[3..$#f] );

   }
   else
   {
       # output non-matching line as-is
       print $_ . qq[\n];
   }
}

作为输出的示例:

1653455 ASDFASDF22 bla bla bla asd xmv                              ASDFASDF22 AA
1944444 ASDFASDF22 klasdfmxvl yxklc erisa ask xdk asdm ase          ASDFASDF22 BB
######################### non-matching line left alone ##########################
1984945 ASDFASDF22 jklyck aklsdfl asfjasl asdkkcii wdkkkxd aslasl w ASDFASDF22 BB

答案4

GNU awk:

awk -F "[[:space:]]+ASDFASDF22[[:space:]]+" \
    'BEGIN { OFS=" ASDFASDF22 "; }
    { 
        $2 = sprintf("%-50s", substr($2, 0, 50));
        print;
    }'

相关内容