Border an array of words in BASH

Viewed 171

I've been learning Bash and my teacher made an exercise that got me puzzled.

I'm just struggling with adding the spaces in front of the words.

The code should account for the number of characters in each word and adjust the number of asterisks and spacing for it to always be aligned.

This is what it should look like:

***********
* Hello   *
* World   *
* good    *
* etceter *
***********

My code:

#determine biggest word
words=("Hello" "World" "good" "etceter")
numchar=0
for i in ${words[@]}; do
    if [ ${#i} -gt $numchar ]
    then
        numchar=${#i}
    fi
done

#write *
a=-4
while [ $a -lt $numchar ]; do
    printf "*"
    ((a++))
done

#write array
echo
for txt in ${words[@]}; do
    space=$(($numchar-${#txt}))
    s=0
    echo "* $txt "
    while [ $s -lt $space ]; do
        printf " "
        ((s++))
        printf "*"
    done
done

#write *
a=-4
while [ $a -lt $numchar ]; do
    printf "*"
    ((a++))
done

I'm struggling with the #write array part.

Many thanks in advance!

4 Answers

You only need a few changes.

#write array
echo
for txt in ${words[@]}; do
    space=$(($numchar-${#txt}))
    s=0
    echo -n "* $txt "           # -n added to not append a newline
    while [ $s -lt $space ]; do
        echo -n " "             # switched from printf to echo (cosmetics)
        ((s++))
        # printf "*"            # commented out
    done
    echo "*"                    # added
done

Your while loop only adds the spaces after the current word. The trailing * comes after the loop to finish this line.

Rewriting the last 3 sections:

# define solid string of asterisks

printf -v stars  '*%.0s' $(seq 1 $(( numchar + 4)) )    # length = numchar + 4

echo "${stars}"

for txt in "${words[@]}"
do
    printf "* %-*s *\n" "${numchar}" "${txt}"
done

echo "${stars}"

This generates:

***********
* Hello   *
* World   *
* good    *
* etceter *
***********

It's hardcoded a bit but think you got the idea:

$ echo '***********'; printf '* %-8s*\n' "${words[@]}"; echo '***********'
***********
* Hello   *
* World   *
* good    *
* etceter *
***********

You were on the right track with getting the length of the longest line first.

Borders and padding can be done entirely with printf format specifiers, and pattern substitution. Use %-Ns to align left, and %Ns to align right.

With correct quoting, you can also have multiple words and spaces in each line.

Here's an example:

lines=('Hello World!'
       'Line two.'
        a-line
       'another line'
       'The end.')

# border character
c='*'

# get length of longest line, required for padding
for i in "${lines[@]}"; do
    ((${#i} > pad)) &&
    pad=${#i}
done

# make a string to fill top/bottom
fill=$(printf %$((pad + 4))s "$c")
fill=${fill// /$c}

# print the text box
printf '%s\n' "$fill"

for line in "${lines[@]}"; do
    printf "$c %-${pad}s $c\n" "$line"
done

printf '%s\n' "$fill"

Output:

****************
* Hello World! *
* Line two.    *
* a-line       *
* another line *
* The end.     *
****************
Related