Issue
I have a bash
script that uses printf
to printout some colored STDOUT. I noticed that sometimes it insert spaces:
#!/usr/bin/env bash
### define colors
BLACK=$(tput setaf 0)
RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
YELLOW=$(tput setaf 3)
LIME_YELLOW=$(tput setaf 190)
POWDER_BLUE=$(tput setaf 153)
BLUE=$(tput setaf 4)
MAGENTA=$(tput setaf 5)
CYAN=$(tput setaf 6)
WHITE=$(tput setaf 7)
BRIGHT=$(tput bold)
NORMAL=$(tput sgr0)
BLINK=$(tput blink)
REVERSE=$(tput smso)
UNDERLINE=$(tput smul)
### 0. CHECK
# 1. docker
echo
printf "%40s\n" " 0.1. checking ${BRIGHT}${GREEN}docker${NORMAL} ..."
if [ ! "$(command -v docker)" ]; then
printf "%40s\n" " -> Please install ${BRIGHT}${GREEN}docker${NORMAL} first: ${BLUE}${UNDERLINE}https://github.com/cccnrc/diagnosticator-mac#dependencies${NORMAL}"
exit 1
else
printf "%40s\n" " -> ${BRIGHT}${GREEN}docker${NORMAL} found"
fi
# 2. docker-compose
printf "%40s\n" " 0.2. checking ${BRIGHT}${GREEN}docker-compose${NORMAL} ..."
if [ ! "$(command -v docker-compose)" ]; then
printf "%40s\n" " -> Please install ${BRIGHT}${GREEN}docker-compose${NORMAL} first: ${BLUE}${UNDERLINE}https://github.com/cccnrc/diagnosticator-mac#dependencies${NORMAL}"
exit 1
else
printf "%40s\n" " -> ${BRIGHT}${GREEN}docker-compose${NORMAL} found"
fi
echo
Why are there much more spaces before -> docker found
than -> docker-compose found
line when the printf
command spaces are exactly the same?
Solution
Color codes also take bytes, but are invisible. You have to take them into account.
printf "%*s\n" \
$((40 + ${#BRIGHT} + ${#GREEN} + ${#NORMAL})) \
" -> ${BRIGHT}${GREEN}docker${NORMAL} found"
In Bash instead of:
if [ ! "$(command -v docker)" ]
(prefer [[
over [
anyway, but) prefer:
if hash docker 2>/dev/null
hash
will hash the command location, which will make any subsequent invocation faster, because Bash will not have to find the command again. And both $(
and [
spawn a subprocess, which is way slower than calling builtin hash
.
Answered By - KamilCuk Answer Checked By - Candace Johnson (WPSolving Volunteer)