Sunday, February 27, 2022

[SOLVED] printf inserts random spaces in stdout

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

I got this output: printd stdout

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)