4
\$\begingroup\$

My goal with the below piece of POSIX shell code was to address the more platforms the better with shell tput colors. With this code, I now start all of my scripts, and so it's time to review it for some things I overlooked, did not think of too well, and such. Note: I start my scripts with set -u, which is why I set all empty in unspecified cases. Thanks.


#!/bin/sh
set -u
if tput setaf > /dev/null 2>&1; then
 # Linux-like
 tput_number_of_colors=$(tput colors 2> /dev/null)
 tput_bold=$(tput bold 2> /dev/null)
 tput_reset=$(tput sgr0 2> /dev/null)
 tput_cmd_set_fg_color='tput setaf'
elif tput AF > /dev/null 2>&1; then
 # BSD-like
 tput_number_of_colors=$(tput Co 2> /dev/null)
 tput_bold=$(tput md 2> /dev/null)
 tput_reset=$(tput me 2> /dev/null)
 tput_cmd_set_fg_color='tput AF'
else
 # Console-like
 tput_number_of_colors=2
 tput_cmd_set_fg_color=
 tput_bold=
 tput_reset=
fi
tput_test ()
{
 [ -n "$tput_number_of_colors" ] && [ -n "$tput_bold" ] && [ -n "$tput_reset" ] &&
 { [ "$tput_number_of_colors" -ge 8 ] && printf '%s' "$tput_bold" && $tput_cmd_set_fg_color 1; } > /dev/null 2>&1
}
if tput_test; then
 color_red=$tput_bold$($tput_cmd_set_fg_color 1)
 color_green=$tput_bold$($tput_cmd_set_fg_color 2)
 color_yellow=$tput_bold$($tput_cmd_set_fg_color 3)
 color_blue=$tput_bold$($tput_cmd_set_fg_color 4)
 color_magenta=$tput_bold$($tput_cmd_set_fg_color 5)
 color_cyan=$tput_bold$($tput_cmd_set_fg_color 6)
 color_white=$tput_bold$($tput_cmd_set_fg_color 7)
else
 color_red=; color_green=; color_yellow=; color_blue=; color_magenta=; color_cyan=; color_white=
fi
asked Oct 9, 2020 at 6:15
\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

Self-review

Since no one replied thus far, I decided to re-think and re-write the code myself this morning.


terminfo (*nix) vs termcap (*bsd)

I never really thought about how important to make note of this actually is. For searching info online, one needs to know these keywords. So, I added them as comments.

Structure into functions

I believe this code should be structured into suitable functions where available.

Find a way for an exit code from those functions

It's needed to simply chain (&&) the commands like tput_bold=$(tput bold 2> /dev/null) && tput_reset=$(tput sgr0 2> /dev/null) in order for the imagined functions to return a reliable exit code.

The most basic test missing

command -v tput was missing in my code, which is remedied now.

No unset variables

Since I use set -u in my scripts, it's necessary to set variables empty in case of failure. This feature has been enhanced.


Modified code

#!/bin/sh
set -u
tput_setup_nix ()
{
 # terminfo
 tput_cmd_set_fg_color='tput setaf'
 tput_number_of_colors=$(tput colors 2> /dev/null) &&
 tput_bold=$(tput bold 2> /dev/null) &&
 tput_reset=$(tput sgr0 2> /dev/null)
}
tput_setup_bsd ()
{
 # termcap
 tput_cmd_set_fg_color='tput AF'
 tput_number_of_colors=$(tput Co 2> /dev/null) &&
 tput_bold=$(tput md 2> /dev/null) &&
 tput_reset=$(tput me 2> /dev/null)
}
tput_setup_none ()
{
 # no unset variables
 tput_cmd_set_fg_color=
 tput_number_of_colors=
 tput_bold=
 tput_reset=
}
if command -v tput > /dev/null 2>&1; then
 if tput setaf > /dev/null 2>&1; then
 if ! tput_setup_nix; then tput_setup_none; fi
 elif tput AF > /dev/null 2>&1; then
 if ! tput_setup_bsd; then tput_setup_none; fi
 else
 tput_setup_none
 fi
else
 tput_setup_none
fi
tput_capability_test ()
{
 [ -n "$tput_cmd_set_fg_color" ] && [ -n "$tput_number_of_colors" ] && [ -n "$tput_bold" ] && [ -n "$tput_reset" ] &&
 [ "$tput_number_of_colors" -ge 8 ] && { $tput_cmd_set_fg_color 1 && printf '%s' "$tput_bold$tput_reset"; } > /dev/null 2>&1
}
if tput_capability_test; then
 color_red=$tput_bold$($tput_cmd_set_fg_color 1)
 color_green=$tput_bold$($tput_cmd_set_fg_color 2)
 color_yellow=$tput_bold$($tput_cmd_set_fg_color 3)
 color_blue=$tput_bold$($tput_cmd_set_fg_color 4)
 color_magenta=$tput_bold$($tput_cmd_set_fg_color 5)
 color_cyan=$tput_bold$($tput_cmd_set_fg_color 6)
 color_white=$tput_bold$($tput_cmd_set_fg_color 7)
else
 color_red=
 color_green=
 color_yellow=
 color_blue=
 color_magenta=
 color_cyan=
 color_white=
fi
answered Oct 22, 2020 at 5:40
\$\endgroup\$
2
  • \$\begingroup\$ I don't see how the command -v tput adds anything, except complexity. If there's no available tput command, then we get error return from trying to execute it. Also, you can simplify if ! tput_setup_nix; then tput_setup_none; fi to simple tput_setup_nix || tput_setup_none. \$\endgroup\$ Commented Oct 11, 2022 at 15:45
  • \$\begingroup\$ @TobySpeight Correct, command -v did not add anything. \$\endgroup\$ Commented Oct 12, 2022 at 22:34
1
\$\begingroup\$

2022 review

I found myself time for another self-review now, two years later.

Main features

  • Simplified code, better readability.

  • Removed unnecessary tests.

  • Shortened code, rather unimportant.


Modified code

# Linux uses terminfo; BSD uses termcap; the null command (:) ignores everything after
tput_init_linux () { set_fg_color='tput setaf'; reset_color=$(tput sgr0 2>/dev/null); }
tput_init_bsd () { set_fg_color='tput AF'; reset_color=$(tput me 2>/dev/null); }
tput_init_none () { set_fg_color=':'; reset_color=; }
# This routine prepares `tput` on Linux and BSD and no color console
if tput setaf >/dev/null 2>&1; then tput_init_linux || tput_init_none;
elif tput AF >/dev/null 2>&1; then tput_init_bsd || tput_init_none;
else tput_init_none; fi
no_color () { printf '%s' "$reset_color"; }
colorize ()
{
 case "1ドル" in
 (red) $set_fg_color 1 ;;
 (green) $set_fg_color 2 ;;
 (yellow) $set_fg_color 3 ;;
 (blue) $set_fg_color 4 ;;
 (magenta) $set_fg_color 5 ;;
 (cyan) $set_fg_color 6 ;;
 (white) $set_fg_color 7 ;;
 (*) printf '%s\n' "This color ('1ドル') is not supported. Quitting!" >&2; exit 1 ;;
 esac
}
color_red=$(colorize red)
color_green=$(colorize green)
color_yellow=$(colorize yellow)
color_blue=$(colorize blue)
color_magenta=$(colorize magenta)
color_cyan=$(colorize cyan)
color_white=$(colorize white)
color_none=$(no_color)
answered Oct 6, 2022 at 3:03
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.