2

I am trying to format my output file so that text in lines is spreaded evenly, to align it both left and right. To do left and right justifying is trivial, but how can one do both left and right with awk?

EDIT

input:

This is a text
that is
not distributed
evenly in a file

desired output should look something like this:

This  is  a text
that          is
not  distributed
evenly in a file
4
  • 5
    Why limit the question to awk? par e.g. is better suited and can do justification by default. (Note that for UTF8 input you might need to patch your par.) Commented May 10, 2016 at 18:55
  • 1
    You could always learn groff. ;) info groff. Are you going for full text justification, i.e. adding extra spaces between words? Commented May 10, 2016 at 18:59
  • can you sahre sample input && desired output? Commented May 10, 2016 at 18:59
  • I am currently learning awk that's why I want to use it to see how I can format my text with it. I just updated my post with the input and output @NullSoulException Commented May 10, 2016 at 19:07

2 Answers 2

2

If you know the target width in advance, you can get basic justification by redistributing the spaces in each line:

#!/usr/bin/awk -f

BEGIN {
    if (width == 0) width = 80
}

NF <= 1 { print }

NF > 1 {
    nbchar = 0
    for (i = 1; i <= NF; i++) {
        nbchar += length($i)
    }
    nbspc = width - nbchar
    spcpf = int(nbspc / (NF - 1))
    for (i = 1; i < NF; i++) {
        printf $i
        spaces = (NF == 2 || i == NF - 1) ? nbspc : spcpf
        if (spaces < 1) spaces = 1
        for (j = 0; j < spaces; j++) {
            printf " "
        }
        nbspc -= spaces
    }
    print $NF
}

(with a default width of 80; override with -v width=...).

This works as follows:

  • lines with no or one field are output as-is;
  • each line with two or more fields is processed:
    • the number of non-field-separator characters is counted (nbchar);
    • this determines the number of spaces to distribute (ncspc);
    • dividing that by the number of fields minus one gives the number of spaces to print between each field (rounded down in spcpf);
    • each field is printed, except the last one; then the appropriate number of spaces is printed — we always ensure there's at least one, and we pick spcpf, except on lines with only two fields, or if we're printing the second last field, in which case it's however many spaces are left (nbspc is adjusted to keep track);
    • finally the last field is printed, with a new line.

If you want to target the existing text's width, initialize width using something like this:

awk 'length > max { max = length }; END { print max }'

(I don't know of a foolproof way of resetting the input stream in awk — you could always specify that it's a file and adapt the script accordingly.)

This produces

This is a   text
that          is
not  distributed
evenly in a file

with width 16 (the existing text's width), or

This   is   a   text
that              is
not      distributed
evenly  in  a   file

with width 20, or

This is a text
that      is
not distributed
evenly in a file

with width 12 (lines overflow then).

2
  • This is good. Maybe process the file twice, first time to get the length of the longest line and use that instead of a user-defined width (that's how I read the question - I might be wrong though). Commented May 10, 2016 at 21:38
  • @don_crissti I wondered about that, given the example... Commented May 10, 2016 at 21:39
0

Here you go.

    cat file1.txt 
    This is a text
    that is
    not distributed
    evenly in a file

You said "lines is spreaded evenly,", so injecting "\t" tab-delimited , should do it for you.

   cat file1.txt | awk '{print $1 "\t" $2 "\t" $3  "\t" $4 }'

 > file2.txt 

Result:

    cat file2.txt 
    This    is  a   text
    that    is      
    not distributed     
    evenly  in  a   file
1
  • Thank you, this helps a lot. But what if I don't know the number of fields on the input? Commented May 10, 2016 at 19:35

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.