Looking for a way to view lines of a text file one-at-a-time centered on screen

Something like that:

#!/usr/bin/env bash

if [ ! "$#" -eq 1 ]
then
    printf "Usage: %s <file>\n" "$0" >&2
    exit 1
fi

file="$1"

display_center(){
    clear
    columns="$(tput cols)"
    lines="$(tput lines)"
    down=$((lines / 2))
    printf '\n%.0s' $(seq 1 $down)
    printf "%*s\n" $(( (${#1} + columns) / 2)) "$1"
}

while IFS= read -r line
do
    display_center "$line"
    read -n 1 -s -r </dev/tty
done < "$file"

Name it centered.sh and use like that:

./centered.sh centered.sh

It will print each line from the given file. Press any key to show the next line. Notice that it's not well tested yet so use with caution and that it'll always print lines starting from the center of the screen so it will make long lines appear more at the bottom.

The first line:

#!/usr/bin/env bash

is a shebang. Additionally, I use env for its features. I tried to avoid Bash and write this script in POSIX shell but I gave up because especially read was very problematic. You should keep in mind that even though it may seem that Bash is ubiquitous it isn't preset everywhere by default, for example on BSD or small embedded systems with Busybox.

In this part:

if [ ! "$#" -eq 1 ]
then
    printf "Usage: %s <file>\n" "$0" >&2
    exit 1
fi

we check if user provided exactly one parameter and if they didn't we print usage info to standard error and return 1, that means an error to a parent process.

Here

file="$1"

we assign filename parameter that user has passed to a variable file that we'll use later.

This is a function that actually prints centered text:

display_center(){
    clear
    columns="$(tput cols)"
    lines="$(tput lines)"
    down=$((lines / 2))
    printf '\n%.0s' $(seq 1 $down)
    printf "%*s\n" $(( (${#1} + columns) / 2)) "$1"
}

There are no function prototypes in Bash so you can't know how many parameters function takes in advance - that one takes only one parameter which is a line to print and it's dereferenced using $1 This functions first clears the screen, then moves down by lines/2 from the top of the screen to reach center of the screen and then it prints centered line using the method I borrowed from here.

That is the loop that reads input file passed by the user and calls display_center() function:

while IFS= read -r line
do
    display_center "$line"
    read -n 1 -s -r </dev/tty
done < "$file"

read is used with -n 1 to read only one character, -s to not echo input coming from a terminal and -r to prevent mangling backslashes. You can learn more about read in help read. We also read from /dev/tty directly because stdin already points to the file - if we didn't tell read to read from /dev/tty the script would very quickly print all lines from the file and exit immediately without waiting for the user to press a key.


You can do it with dialog package:

file=lorem                             #Path to the file to be displayed
ln=1                                   #Current line number to be displayed
nlines=$(wc -l "$file"|cut -f1 -d" ")  #Total number of lines of file
while [ "$ln" -le "$nlines" ]; do
    line=$(sed -n "$ln p" "$file")     #sed gets current line
    if dialog --yes-label Previous --no-label Next \
    --default-button no --yesno "$line" 5 100; then
        ln=$((ln-1))
    else
        ln=$((ln+1))
    fi
done

It is a text-based presentation (I took "bare-bones slide show" seriously!), no X session required, that displays one line at a time. You can go backwards or forwards and it ends after the last line.