Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Using bash on Linux, how can I process a text file such that space is inserted before a certain column so that column is aligned in the output? For example:

Input

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

Output

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

The columns between the two ASDFASDF22s must be less than 50 characters, or it should be truncated.

share|improve this question

6 Answers 6

up vote 5 down vote accepted

One solution using perl:

Content of script.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] );
}

Execute the script:

perl script.pl infile

And output:

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
share|improve this answer
    
omg. this answer is great! –  LanceBaynes Dec 22 '11 at 18:51

Using bash's arrays

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
share|improve this answer
    
Nice. read -r is generally recommended over plain read. –  jw013 Dec 22 '11 at 20:17
    
Thanks. I also neglected the -a option. –  glenn jackman Dec 22 '11 at 20:31

I tried @Birei's script on a text file I needed to columnize, but it failed because the file contained some lines that didn't match the given delimiter (and didn't need to be columnized). So with my poor knowledge of perl, I added a simple check of the size of the array to avoid processing non-matching lines. I'll post the basic code here in case someone else needs this change.

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];
   }
}

So as an example of the output:

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
share|improve this answer
f=open("filename","r") 

a=[]

for line in f:

    if line[-1:]=='\n':
        line=line[:-1]

    a=line.split("ASDFASDF22")

    a.insert(1,"ASDFASDF22")

    a.insert(len(a)-1,"ASDFASDF22")

    k1=len(a[2])

    if k1 > 50:
        k2=k1-50
        k2=k2+1
        a[2]=a[2][:-k2]
        for i in a:
            print i,
    else:
        k2=50-k1
        for i in range(0,len(a)):
            if i !=2:
                print a[i],
            else:
                for j in range(0,k2):
                    a[2]=a[2]+" "
                print a[2],
    print ""`

This is a naive implementation in python. Save this as filename.py and give python filename.py.

share|improve this answer

GNU awk:

awk -F "[[:space:]]+ASDFASDF22[[:space:]]+" \
    'BEGIN { OFS=" ASDFASDF22 "; }
    { 
        $2 = sprintf("%-50s", substr($2, 0, 50));
        print;
    }'
share|improve this answer
while read -r one two line
do  printf "%s %s %-50.50s% %s\n" \   
       "$one" "$two" "${line%%"$two"*}" "$two${line#*"$two"}"         
done <<\DATA
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
1984945 ASDFASDF22 jklyck aklsdfl asfjasl asdkkcii wdkkkxd aslasl wqe hjbiub kuvyukvbklhb khuvbukvbuybouin ASDFASDF22 BB
DATA

You can do the above with most any POSIX shell.

OUTPUT

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
1984945 ASDFASDF22 jklyck aklsdfl asfjasl asdkkcii wdkkkxd aslasl wqe ASDFASDF22 BB
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.