Bash script to center fortune/text from stdin/pipe

Iacchus

I am using a little script in python3 to show centered fortunes in console, can you suggest me how to do this in pure bash?

file: center.python3

#!/usr/bin/env python3

import sys, os

linelist = list(sys.stdin)

# gets the biggest line
biggest_line_size = 0
for line in linelist:
    line_lenght = len(line.expandtabs())
    if line_lenght > biggest_line_size:
        biggest_line_size = line_lenght

columns = int(os.popen('tput cols', 'r').read())
offset = biggest_line_size / 2
perfect_center = columns / 2
padsize =  int(perfect_center - offset)
spacing = ' ' * padsize # space char

text = str()
for line in linelist:
    text += (spacing + line)

divider = spacing + ('─' * int(biggest_line_size)) # unicode 0x2500
text += divider

print(text, end="\n"*2)

Then in .bashrc

After making it executable chmod +x ~/center.python3:

fortune | ~/center.python3

EDIT: Later I will try to reply to this OP based on the comment I had, but for now I made it more literate.

EDIT 2: updating the python script to solve a bug as pointed out by @janos about tab expansion.

enter image description here

xhienne

Here is my script center.sh:

#!/bin/bash

readarray message < <(expand)

width="${1:-$(tput cols)}"

margin=$(awk -v "width=$width" '
    { max_len = length > width ? width : length > max_len ? length : max_len }
    END { printf "%" int((width - max_len + 1) / 2) "s", "" }
' <<< "${message[@]}")

printf "%s" "${message[@]/#/$margin}"

How it works:

  • the first command puts each line of stdin in array message after converting tabulations to spaces (thanks to @NominalAnimal)
  • the second command reads the window width from parameter #1 and put it in variable width. If no parameter is given, the actual terminal width is used.
  • the third command sends the whole message to awk in order to produce the left margin as a string of spaces which is put in variable margin.
    • the first awk line is executed for each input line. It calculates max_len, the length of the longest input line (capped to width)
    • the second awk line is executed when all input lines have been processed. It prints a string of (width - max_len) / 2 white space characters
  • the last command prints every line of message after prepending margin to them

Test :

$ fortune | cowthink | center.sh
                    _______________________________________
                   ( English literature's performing flea. )
                   (                                       )
                   ( -- Sean O'Casey on P. G. Wodehouse    )
                    ---------------------------------------
                           o   ^__^
                            o  (oo)\_______
                               (__)\       )\/\
                                   ||----w |
                                   ||     ||

$ echo $'|\tTAB\t|' | center.sh 20
  |       TAB     |

$ echo "A line exceeding the maximum width" | center.sh 10
A line exceeding the maximum width

Finally, if you want to end the display with a separation line, like in your Python script, add this line before the last printf command:

message+=( $(IFS=''; sed s/./─/g <<< "${message[*]}" | sort | tail -n1)$'\n' )

What it does is replace every character in every line with a , select the longest with sort | tail -n1, and add it at the end of the message.

Test:

$ fortune | center.sh  60
     Tuesday is the Wednesday of the rest of your life.
     ──────────────────────────────────────────────────

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related