0

How to format the following input strings to output strings using sed?

The center string should start at 20th character and end string should start at 40th character.

input:

begining center end     
beg12  cen12  end12
beg13 cen  end

output:

begining     center      end     
beg12        cen12       end12
beg13        cen         end
1
  • 3
    how about using column -t file?
    – StefanR
    May 17, 2017 at 6:55

6 Answers 6

2

awk may be used to format this data with its printf() function.

$ awk '{ printf("%-20s%-20s%s\n", $1, $2, $3) }' data.in
begining            center              end
beg12               cen12               end12
beg13               cen                 end

This assumes that the data in the file is whitespace-separated.

To give it the column width as a parameter:

$ cols=40
$ awk -v c="$cols" 'BEGIN { fmt=sprintf("%%-%ds%%-%ds%%s\n", c, c) } { printf(fmt, $1, $2, $3) }' data.in
begining                                center                                  end
beg12                                   cen12                                   end12
beg13                                   cen                                     end
1
  • this is cleaner than my answer. and one of the only times I've ever seen awk as a superior solution to more basic text processing tools like sed May 17, 2017 at 7:41
1

This is one of those occasions where I wouldn't use sed, I would use printf, particularly the
%-Ns format which will pad the string with blanks until the "field" occupies a minimum of N characters

#!/usr/bin/env bash

while read first second third
do
    printf "%-20s%-20s%s\n" "$first" "$second" "$third"
done <<- 'EOF' 
    begining center end     
    beg12  cen12  end12
    beg13 cen  end
EOF
1

awk approach:

awk '{printf("%-20s%-20s%-20s\n",$1,$2,$3)}' file

The output:

begining            center              end                 
beg12               cen12               end12               
beg13               cen                 end 
1

You already got answers with other tools, column being the most obvious. I agree that sed is not the tool of choice for this, but if you already use sed to get the table, it's nasty to pipe that output to another tool just for formatting. In this case use something like this at the end of your script:

sed 's/  */    /g;s/ /     /g;s/\(.\{20\}\) */\1/g'

This replaces all groups of spaces by four spaces, then each space by five spaces, so we have padded 20 spaces. The third s command keeps the first 20 chars of each column and removes remaining spaces.

4
  • 1
    if you use sed in extended regex mode you could do: sed -r 's/ */ /g;s/ / /g;s/(.{20}) */\1/g' its a bit cleaner May 17, 2017 at 7:43
  • 1
    Agreed, but I think that -E is more portable for ERE usage than -r (some versions support both, some only -E). Btw, the multiple spaces got lost in your comment, maybe due to the comment formatting.
    – Philippos
    May 17, 2017 at 7:47
  • interesting, my preference is to use -E because you can just think if it as "extended" and thats consistent with grep as well, but I used -r because my sed (gnu sed) doesn't mentioned -E anywhere, so I thought -E was deprecated as not being portable May 17, 2017 at 8:01
  • According to GNU -r/-E historically was a GNU extension, but the -E extension has since been added to the POSIX standard (austingroupbugs.net/view.php?id=528), so use -E for portability. GNU sed has accepted -E as an undocumented option for years, and *BSD seds have accepted -E for years as well, but scripts that use -E might not port to other older systems. So they suggest using -E except for old GNU systems. No idea why they don't include it in the man page and say -r is deprecated.
    – Philippos
    May 17, 2017 at 8:25
1
< yourfile tr -s '\t ' '\t\t' | expand -t 19,39

Results

         1         2         3         4         5
12345678901234567890123456789012345678901234567890
begining           center              end
beg12              cen12               end12
beg13              cen                 end

Working

  • First we squeeze out all residual spaces and/or TABs to TABs only.
  • Then we apply the expand command on the resultant by using the -t option and listing out the tab positions.
0
sed 's/  */    /g;s/ /     /g;s/\(.\{20\}\) */\1/g' 

-> This gives space in every word.

beginning and end has only one word. center has multiple words.

beginning          center cntr cnt center              end
beg12              cen12  cnt cntr                     end12
beg13              cen center                          end
3
  • How is this different from the answer given by @Philippos ?
    – Kusalananda
    May 17, 2017 at 22:01
  • sed 's/ */ /g;s/ / /g;s/(.\{20\}) */\1/g' Adds more spaces in every center words. It should give only one space between center words.
    – spiderman
    May 17, 2017 at 22:29
  • Any sed answer for String spaces ?
    – spiderman
    May 18, 2017 at 6:40

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .