user2023
user2023

Reputation: 478

How to format the vaiable output uing printf in a columner way

I have below script which returns the output of the some variables, i am using printf to align the output format but i'm not able to make it correctly formatted either right-justify or left-justify.

Any help will be much appreciated.

Script:

#!/bin/bash
read -rsp $'Please Enter password below: ' SSHPASS
echo -n  ""
export SSHPASS

print "\n"
printf "Hostname        CPU     MEM     SWAP"
remote_connect() {
   target_host=$1
        mem=$(sshpass -e ssh -o StrictHostKeyChecking=no -q -t "$target_host" free -g | /bin/awk '/^Mem/{print $2}')
        swap=$(sshpass -e ssh -o StrictHostKeyChecking=no -q -t "$target_host" free -g | /bin/awk '/^Swap/{print $2}')
        cpu=$(sshpass -e ssh -o StrictHostKeyChecking=no -q -t "$target_host" grep -c proc /proc/cpuinfo)
    printf "%-20s %10s %10s %5s\n" "$target_host" "${cpu} ${mem} ${swap}" 
}  2>/dev/null
export -f remote_connect
< /home/cpls/mb_hosts xargs -P5 -n1 -d'\n' bash -c 'remote_connect "$@"' --

Result:

Hostname        CPU     MEM     SWAP
cpl1855.ind-blr01.cpl.com  4  2  8
cpltp064.ind-blr01.cpl.com  2  1  8
cpltp065.cdi.eu-cdc01.cpl.com  2  1  8
cpl1856.cdi.de-hbg01.cpl.com  2  2  8
cpl1853.cdi.eu-cdc01.cpl.com  2  1  8
cpl1854.cn-sha01.cpl.com  2  1  8
cpl1983.cdi.am-cdc01.cpl.com  2  1  8
cpl1984.cdi.am-cdc01.cpl.com  2  1  8
cpl1986.cdi.am-cdc01.cpl.com  2  1  8

Expected:

There is a utility shipped with RHEL systems called column which is used to columnate lists.

$ cat tt | column -t
Hostname                       CPU  MEM  SWAP
cpl1855.ind-blr01.cpl.com      4    2    8
cpltp064.ind-blr01.cpl.com     2    1    8
cpltp065.cdi.eu-cdc01.cpl.com  2    1    8
cpl1856.cdi.de-hbg01.cpl.com   2    2    8
cpl1853.cdi.eu-cdc01.cpl.com   2    1    8
cpl1854.cn-sha01.cpl.com       2    1    8
cpl1983.cdi.am-cdc01.cpl.com   2    1    8
cpl1984.cdi.am-cdc01.cpl.com   2    1    8
cpl1986.cdi.am-cdc01.cpl.com   2    1    8

Upvotes: 0

Views: 147

Answers (2)

L&#233;a Gris
L&#233;a Gris

Reputation: 19625

read -rsp $'Please Enter password below: ' SSHPASS
echo -n  ""
export SSHPASS

Why do you read the password masked but then export expose it to the whole session environment?

I'd use an ssh key pair with a restricted commands set.

        mem=$(sshpass -e ssh -o StrictHostKeyChecking=no -q -t "$target_host" free -g | /bin/awk '/^Mem/{print $2}')
        swap=$(sshpass -e ssh -o StrictHostKeyChecking=no -q -t "$target_host" free -g | /bin/awk '/^Swap/{print $2}')
        cpu=$(sshpass -e ssh -o StrictHostKeyChecking=no -q -t "$target_host" grep -c proc /proc/cpuinfo)
  • If you want to parse the output of free -g, you need to set the locale to C with: LC_ALL=C free -g, or the awk pattern will fail a match on non-US English locale.
  • This needlessly establishes 3 distinct ssh sessions to recover data you could get in one go with:
  read -r mem swap cpu < <(
    ssh -o StrictHostKeyChecking=no -q -t "$target_host" \
      awk '/^MemTotal/{printf("%d\t", $2/1000000)};/^SwapTotal/{printf("%d\t", $2/1000000)};/^processor/{c++};END{print c}' /proc/meminfo /proc/cpuinfo
  )

Or even better with only access to cat, download the data and parse locally:

  read -r mem swap cpu < <(
    ssh -o StrictHostKeyChecking=no -q -t "$target_host" \
      cat /proc/meminfo /proc/cpuinfo | 
        awk '/^MemTotal/{printf("%d\t", $2/1000000)};/^SwapTotal/{printf("%d\t", $2/1000000)};/^processor/{c++};END{print c}'
  )

Your snippet fixed:

#!/usr/bin/env bash

read -rsp $'Please Enter password below: ' SSHPASS

export SSHPASS

printf '\n%-32s %10s %10s %5s\n' 'Hostname' 'CPU' 'MEM' 'SWAP'
remote_connect() {
  target_host=$1
  read -r mem swap cpu < <(
    sshpass -e ssh -o StrictHostKeyChecking=no -q -t "$target_host" \
      cat /proc/meminfo /proc/cpuinfo |
      awk '/^MemTotal/{printf("%d\t", $2/1000000)};/^SwapTotal/{printf("%d\t", $2/1000000)};/^processor/{c++};END{print c}'
  )
  printf "%-32s %10s %10s %5s\n" "$target_host" "$cpu" "$mem" "$swap"
} 2>/dev/null
export -f remote_connect

< /home/cpls/mb_hosts xargs -P5 -l1 bash -c 'remote_connect "$1"' --

Example output:

Hostname                                CPU        MEM  SWAP
localhost                                 8         24     6

Upvotes: 3

Paul Hodges
Paul Hodges

Reputation: 15408

Your formatting problem (aside from passing the wrong number of arguments originally) is that you are defining less space for your first field than some of its data elements require.

I put the data in a file called data (the formatting isn't about how you acquire the field data).

$: fmt="%-30s %10s %10s %5s\n"
$: printf "$fmt" Hostname        CPU     MEM     SWAP &&
   while read -r -a dat; do printf "$fmt" "${dat[@]}"; done < data
Hostname                              CPU        MEM  SWAP
cpl1855.ind-blr01.cpl.com               4          2     8
cpltp064.ind-blr01.cpl.com              2          1     8
cpltp065.cdi.eu-cdc01.cpl.com           2          1     8
cpl1856.cdi.de-hbg01.cpl.com            2          2     8
cpl1853.cdi.eu-cdc01.cpl.com            2          1     8
cpl1854.cn-sha01.cpl.com                2          1     8
cpl1983.cdi.am-cdc01.cpl.com            2          1     8
cpl1984.cdi.am-cdc01.cpl.com            2          1     8
cpl1986.cdi.am-cdc01.cpl.com            2          1     8

As you obviously already demonstrate, you can set minimum field widths and left-justify with a leading dash (-): -

$: printf "/%-5s/%4s/%3s/%2s/\n" abc def ghi jkl mno pqr stu vwx yz.
/abc  / def/ghi/jkl/
/mno  / pqr/stu/vwx/
/yz.  /    /   /  /

The issue was that if your data is wider than the minimum width the full field is printed (the last field), but otherwise it space-pads (the first two fields).

As an aside, you can add maximum field widths, at the risk of losing info -

$: printf "/%5.5s/%4.4s/%3.3s/%2.2s/\n" abc def ghi jkl mno pqr stu vwx yz.
/  abc/ def/ghi/jk/
/  mno/ pqr/stu/vw/
/  yz./    /   /  /

Note that l and x are lost when the field length truncates them.
That's probably not what you want, though there are times...

Upvotes: 2

Related Questions