1

I am trying to implement a shell function to print a specific number of "space" characters, to provide padding for fixed-width console output.

#!/bin/bash

function printWhiteSpaces
{
  local i="122"
  local len="$1"
  local whitespace=' '
  local k=`expr $i - $len`
  while [ $k -gt 0 ]
  do
    echo "${whitespace}"
    ((k--))
  done
}

The above function takes in a single argument as a "length of something", then I take the difference of the desired field width (122) and the argument $1. And I wish to print that many whitespace characters.

Why won't the above print any whitespaces? If anyone has a solution or an improvement to the above function please share. In particular I want to know if there's a better way to write this function that prints concatenated whitespace characters.

Solution so far:

#!/bin/bash

function printWhiteSpaces
{
  local i="122"
  local len="$1"
  local k=`expr $i - $len`
  local whitespace=' '
  while [ $k -gt 0 ]
  do
    echo -n "${whitespace}"
    ((k--))
  done
}
0

3 Answers 3

4

If your aim is to simply print a string variable with a fixed, whitespace-padded field length, I would recommend using the printf function of bash:

printf "%122s" "$myvar"

will print the content of $myvar with as much space to the left as is necessary to fill 122 characters in total.

Try this simple test (field width taken as 20 for readability):

~> myVar="Hi, there!"; printf '%20s\n' "$myVar"
          Hi, there!
~> myVar="Bye!"; printf '%20s\n' "$myVar"
                Bye!

Your original approach didn't work because echo will implicitly print a newline at the end.

If you want to use a shell loop and only echo, you have to call it as echo -n to inhibit the newline:

~> myVar="Bye!"; l=${#myVar}; for ((i=20;i>l;i--)); do echo -n ' '; done; echo "$myVar"
                Bye!
6
  • @ChristopherTruong Note that printfrequires a format string as its first argument.
    – Kusalananda
    Mar 17, 2021 at 8:50
  • While the printf seems like a better solution, if you're determined to use echo, you could make 'whitespace' a string of 122 spaces and do something like echo "${whitespace:0:`expr $i - $len`}" Mar 17, 2021 at 8:55
  • @BrandonXavier Your suggestion gave me only a single character.
    – Chris
    Mar 17, 2021 at 9:02
  • My mistake - replace the `expr $i - $len` with just $k (the expr won't see the unexported variables) Mar 17, 2021 at 9:04
  • Like this: echo -n "${whitespace:0:$k}" ? I still get a single character.
    – Chris
    Mar 17, 2021 at 9:11
1

This script (tested with bash and sh):

#!/bin/sh

function printWhiteSpaces() {
  local i="122"
  local len="$1"
  local k=`expr $i - $len`
  local whitespace='                                                                                                                                                                  '
  echo "${whitespace:0:$k}" test
}

printWhiteSpaces 100
printWhiteSpaces 110
printWhiteSpaces 120

Produced the following output, which I believe is what you wanted:

                       test
             test
   test

(This was done on a Mac - doubt that would make a difference though)

3
  • sh on a mac might be some feature-rich shell. function foo() is a ksh-ism, the POSIX declaration is just foo() { ... }. You could use $(( i - len )) instead of expr and And ${whitespace:0:$k} sadly isn't posix, so won't work on a feature-restricted sh like Dash.
    – ilkkachu
    Mar 17, 2021 at 11:44
  • Just tested on a CentOS 7.9 system - the script behaved correctly under both bash and sh, and with/without the function in the declaration (which, BTW, was copied from the OP script) Mar 17, 2021 at 13:21
  • 1
    sh on CentOS might also be Bash. I don't doubt it works on Bash, I'm just pointing out that foo() works more widely, without a downside. Debian/Ubuntu has Dash as /bin/sh by default, and it's not once or twice that people have tripped on that when implicitly assuming all shells are Bash. See e.g. wiki.ubuntu.com/DashAsBinSh and lwn.net/Articles/343924 . Busybox's sh is similar to Dash, and comes up often-ish on embedded systems.
    – ilkkachu
    Mar 17, 2021 at 13:35
0

Inside the function we can tamper with the command line . So we freshly create a command line of $k number of arguments (all null). After the construction is done we echo the command line $* in double quotes will give IFS first char(= space ) separated arguments and since the arguments were all null, we will see only a sea of spaces.

function printWhitespaces
{
  local i="122"
  local len="$1"
  local whitespace=' '
  local k=`expr $i - $len`
  set -- ""
  while [ "$#" -le "$k" ]
  do
    set -- "$@" "$1"
  done
  echo "$*"
}

And another approach, if you already have computed the $k variable is:

printf '%*s\n' "$k" ""

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .