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.