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.

I coded the following to display data formatted in columns:

str1='hello i      am robert
and your ma frnd'

str2='thisisaverylongword thisistoohehehe andherefinishthe         string
hereis a other linefortheexample'

IFS=$'\n'
echo '----------------------'
echo 'STRING SHORT'
echo '----------------------'
echo "$str1" | column -t
echo
echo '----------------------'
echo 'STRING LONG'
echo '----------------------'
echo "$str2" | column -t

Which outputs:

----------------------
STRING SHORT
----------------------
hello  i     am  robert
and    your  ma  frnd

----------------------
STRING LONG
----------------------
thisisaverylongword  thisistoohehehe  andherefinishthe  string
hereis               a                other             linefortheexample

Ok, now I'm trying to format the string with the same pattern, but without merge them.

This is the result I'm looking for:

----------------------
STRING SHORT
----------------------
hello                i                am                robert
and                  your             ma                frnd

----------------------
STRING LONG
----------------------
thisisaverylongword  thisistoohehehe  andherefinishthe  string
hereis               a                other             linefortheexample

Do you have any idea to do it? May be merging the strings and splitting it before the format?

Note that this is only an example, I'm looking for a generic solution, not only for this specific case.

share|improve this question

1 Answer 1

up vote 1 down vote accepted

You will have to

printf "%s\n" "$str1" "$str2" | column -t

and then inject the headers

Generically, I'd write something like this that uses arrays:

strings=( "$str1" "$str2" ... )
headers=( "STRING SHORT" "STRING LONG" ... )

exec 3< <( printf "%s\n" "${strings[@]}" | column -t )
for (( i=0; i<${#strings[@]}; i++)); do
    printf -- "----\n%s\n----\n" "${headers[i]}"
    n=$(wc -l <<< "${strings[i]}")
    for (( j=1; j<=n; j++ )); do
        IFS= read -r line <&3
        echo "$line"
    done
    echo
done
exec 3<&-

Notes:

  • <( ... ) is a bash process substitution. That is a plain pipeline that gets handled as a filename. It's very handy in situtation where you would use a pipe but can't have the right side of the pipe executed in a subshell.
  • here, we are opening file descriptor # 3 to read data from this "file": exec 3<file
  • read -r line <&3 reads a line of data from the process substitution
  • exec 3<&- closes the file descriptor
  • read more about redirections here: http://www.gnu.org/software/bash/manual/bashref.html#Redirections
  • I could have used a printf ... | while read line; do ...; done but I thought the for loops would make the counting easier.
share|improve this answer
    
Thanks! Works perfect! could you add explicative comments, please? I'm really interested in it. :) –  John Doe Mar 24 at 21:03
1  
Any specific questions? Everything in there is documented in the bash manual: gnu.org/software/bash/manual/bashref.html –  glenn jackman Mar 24 at 21:21
    
There is an issue: If the first string of strings is empty strings=("" "$str1" "$str2" ... ), then prints the line of the next string. –  John Doe Apr 4 at 8:29

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.