This post is about a simple trick for printing a horizontal rule in the Terminal, but I would like to start by saying that the headline is not entirely an attempt at humor. I spent a long time working with the limitations of echo, with its -e annoyances and -n inconsistencies between shells. Then I started using printf more, and it’s made string formatting and terminal output so much simpler. Check out the man page (and some more info on format strings)if you’re not already familiar with it.
As a quick example, my most frequent use of printf is outputting shell arrays. What would normally require a loop with echo is a single line with printf:
# Output a Markdown bulleted list of all applescript files
printf '* %s\n' *.applescript
# or
declare -a arrayvars=( one two three )
printf '* %s\n' ${arrayvars[@]}
The rule function
One feature I just recently learned about is variable substitution in format strings. A token in the format string can use an asterisk (*) to accept a variable from the input as a number for the width. This is what the rule function uses:
With that function loaded in Bash, you can run rule to output a horizontal string of hyphens the full width of the terminal:
It’s a handy snippet for using inside of other functions and scripts to separate output or call attention to an output section.
Explanation
A quick breakdown:
printf -v _hr assigns the result of the string interpolation to the variable “_hr”
%*s waits for numeric input to define the width of the string, which in this case will be output as that number of spaces
$(tput cols) is replaced with the number of columns in the current terminal as reported by tputs (passed to the %*s)
If the command is successful (&&), the variable is output with Bash substitution (${var//s/r}) to replace the spaces with a -
The character used for the horizontal rule is pulled from the first argument ($1), and defaults to “-“ if the argument is null (${1--}). It only accepts a single character if you want a single line. If you want a double line, use two characters (==), and so on. You can use any character you want, including extended ascii or unicode with some echo -e work: