2
biwhite=$(tput bold)$(tput setaf 7)
color_off=$(tput sgr0)

printf "%s$USER%s at %s$HOME%s has path %s$PATH%s" "$biwhite" "$color_off" "$biwhite" "$color_off" "$biwhite" "$color_off"

Is there a printf shortcut to avoid having to define every %s when I want to add color to only certain parts of a statement?

Entering "$biwhite" "$color_off" 3 times seems redundant.

3
  • Not an unreasonable thing to ask -- many other languages have a way to refer to a specific positional parameter in their format strings. Commented Feb 14, 2017 at 21:34
  • Like zsh? ducks Commented Feb 14, 2017 at 21:49
  • 1
    You shouldn't put $USER, $HOME and $PATH in the format string for the same reason as you might not want to just put $biwhite and $color_off in the format string: if they contain percent signs, you have a problem. Commented Feb 14, 2017 at 22:38

3 Answers 3

2

It's good practice to avoid putting parameter expansions in the format string of printf, in case they contain percent signs as well. That said, parameter substitution offers a way around some of the repetitiveness.

w="${biwhite}X${color_off}"

printf "%s at %s has path %s" "${w/X/$USER}" "${w/X/$HOME}" "${w/X/$PATH}"

It's not foolproof, but it's fairly unlikely that X will appear in the output of tput. You can pick a longer string instead, at the cost of more typing.

I'm afraid, though, that adding color codes to a string is inherently painful.

Sign up to request clarification or add additional context in comments.

1 Comment

Very good answers from everyone! I'm going with @chepner because I think the answer "I'm afraid, though, that adding color codes to a string is inherently painful." is probably the most useful one to know :|
1

I think you could write a bash function:

biwhite=$(tput bold)$(tput setaf 7)
color_off=$(tput sgr0)

whiten() {
  echo "$biwhite$1$color_off"
}

echo "$(whiten "$USER") at $(whiten "$HOME") has path $(whiten "$PATH")"

Also, why use printf if you're not using any of it's formatting capabilities?

4 Comments

The real question is, rather, why use echo instead of printf?
Moreover, you're suggesting OP to replace good code with lots of subshells... that's not really nice.
Using printf over echo is directly advised by the POSIX specification for echo
...echo's behavior is undefined by the standard (and diverges between implementations) under a number of common circumstances, notably including any case where the arguments being passed may include a backslash literal. Notably, the behavior of bash with and without the xpg_echo flag enabled (and with and without the posix flag in conjunction with xpg_echo) is one of these points of divergence.
0

Provided below is a function which colorizes every other argument, starting with the second. (Thus, a non-colorized prefix can be provided by passing a non-empty string in this first position, or a colorized one by leaving it empty, as here).

Notably, no subshells are involved in this code's execution except in the tput invocations used for demonstrative purposes. It is thus, while verbose, very low-overhead to execute.

biwhite=$(tput bold)$(tput setaf 7)
color_off=$(tput sgr0)

# colorize every other argument, starting from the 2nd.
colorize_words() {
  local start_color end_color
  : "${start_color:=$biwhite}" "${end_color:=$color_off}"
  while (( $# )); do
    printf '%s' "$1"
    shift || break
    printf '%s%s%s' "$start_color" "$1" "$end_color"
    shift || break
  done
  printf '\n'
}

colorize_words "" "$USER" " at " "$HOME" " has path " "$PATH"

This can be customized by passing start_color and end_color values to an individual invocation; for example:

# this prints every other argument in red
start_color=$(tput setaf 1) colorize_words "hello " "cruel " world

1 Comment

Thank you very much, Charles. You always have great answers.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.