How to control the length of the line based on the length of the variable and be able to make the line uniform

Viewed 57

I have the following function:

function separator_text() {

  char="─"
  text="${1}"
  linelen="20"
  filler=""

  filler=$(printf "${char}%.0s" $(seq 1 "${linelen}"))

  printf "%s%s%s" "${filler}" " ${text} " "${filler}"

  printf "\n" # print new line

}

separator_text "normal text"
separator_text "short text"
separator_text "long text - long text"

output:

──────────────────── normal text ────────────────────
──────────────────── short text ────────────────────
──────────────────── long text - long text ────────────────────

I want to control the length of the line based on the length of the variable and be able to make the line uniform.

someone could help me with this little problem.

Desired result:

─────────── normal text ───────────
──────────── short text ───────────
───── long text - long text ───────
3 Answers

You can do it in a slightly differ manner rather easily. Essentially store a line of '─' that has your desired number of total characters. Get the midpoint number of characters (e.g. length / 2 ) and then just output the line followed by '\r' to reset the cursor to start.

Then take your word or phrase you want to overlay on the line and find its length. You know then the " phrase " (space phrase space) will need to start at start=$((midpoint - phrase_len/2 - 1)) characters from the start of the line. Now just move the cursor that many spaces and output your phrase using the ANSI escape \033[<N>C where <N> is the number of characters to move -- $start in this case.

#!/bin/bash

filler="───────────────────────────────────"  # string of filler to width
length=${#filler}                             # length of filler
mid=$(((length)/2))                           # midpoint of filler

for word; do                                  # loop over all positonal parameters
  wordlen=${#word}                            # get length of word
  start=$((mid-wordlen/2-1))                  # compute start of word overfiller
  printf "%s\r" "$filler"                     # output filler with CR
  printf "\033[${start}C %s \n" "$word"       # move cursor start-1, output " word "
done

(note: you can actually combine both printf statements into one, but they have been left separate for readability)

Example Use/Output

An example with the above script in septext.sh that reads all words or phrases given as arguments to the script and outputs them formatted as you desire would be:

$ bash septext.sh "normal text" "short text" "long text - long text"
─────────── normal text ───────────
─────────── short text ────────────
────── long text - long text ──────

Which matches your output (the lines are even in the terminal), but given whatever SO uses for the character spacing shows a bit shorter on the last line. (also all comments in the script are evenly aligned...)

To keep your line size fixed at linlen, you need to do a bit of math to calculate the size of the filler before text and the size of the filler after text since they may be different by one character depending on whether the total number of filler characters is even or not:

#!/bin/bash
  
separator_text() {
  local char="─"
  local text=$1
  local linelen=40   # length of all characters in the final line

  total_fillers=$((linelen - ${#text} - 2))   # 2 spaces
  filler_before=$(printf "$char%.0s" $(seq 1 "$((total_fillers / 2))"))
  filler_after=$filler_before

  # if the number of fillers is not even, it needs one extra
  ((extra_filler = total_fillers % 2))
  if ((extra_filler == 1)); then
    filler_after+=$char  # add extra to after text filler
  fi;

  printf "%s%s%s\n" "$filler_before" " $text " "$filler_after"
}

separator_text "normal text"
separator_text "short text"
separator_text "long text - long text"

This produces your desired output:

$ ./printf.sh
───────────── normal text ──────────────
────────────── short text ──────────────
──────── long text - long text ─────────

If you want the text to line up at the beginning of the text in the first two lines, add the extra filler character to filler_before instead of filler_after, and you'll get this output:

$ ./printf.sh
────────────── normal text ─────────────
────────────── short text ──────────────
───────── long text - long text ────────

Note, linelen must be at least four characters longer than text. Also, if linelen is not even, the text alignment described for the first two lines, reverses.

I appreciate your help, below I share my solution with the difference that the text is aligned to the left.

#!/usr/bin/env bash

print_separator() {
  # usage
  # print_separator "${separator_text}" "${separator_text_color?}" "${divider_color?}"

  local separator_text="${1}"          # text separator
  local separator_text_color="${2-91}" # default color is Light red or get color from 2th argument
  local divider_color="${3-35}"        # default color is Magenta or get color from 3rd argument
  local end_color_reset="\e[0m"        # resets all colors and attributes.

  # variables separator

  local linelen_limit="20"
  local linelen_uniform=$(("${linelen_limit}" - "${#separator_text}"))
  local linelen_full="30"

  local linelen=$(("${linelen_uniform}" + "${linelen_full}"))

  local char="─"
  local text="${separator_text}"
  local filler=""
  filler=$(printf "${char}%.0s" $(seq 1 "${linelen}"))

  printf "\n" # print new line

  # separator start
  printf "\e[${divider_color}m%s${end_color_reset}" "│"
  printf "\e[${divider_color}m%s${end_color_reset}\e[${separator_text_color}m%s${end_color_reset}" "${filler:0:2}" " ${text} " "${filler}"
  printf "\e[${divider_color}m%s${end_color_reset}\n" ">>>"
  # separator end

  printf "\n" # print new line
}


print_separator "normal text"
print_separator "short text"
print_separator "long text - long text"
print_separator "very long text - very long text - very long text"

Output:

│── normal text ───────────────────────────────────────>>>


│── short text ────────────────────────────────────────>>>


│── long text - long text ─────────────────────────────>>>


│── very long text - very long text - very long text ──>>>

output colot

Related