27

My script:

date
echo -e "${YELLOW}Network check${NC}\n\n"

while read hostname
do

ping -c 1 "$hostname" > /dev/null 2>&1 &&

echo -e "Network $hostname : ${GREEN}Online${NC}" ||
echo -e "${GRAY}Network $hostname${NC} : ${RED}Offline${NC}"

done < list.txt
        sleep 30
clear
done

Is outputting info like this:

Network 10.x.xx.xxx : Online   
Network 10.x.xx.xxx : Offline   
Network 10.x.xx.xxx : Offline   
Network 10.x.xx.xxx : Offline   
Network 10.x.xx.x : Online   
Network 139.xxx.x.x : Online   
Network 208.xx.xxx.xxx : Online   
Network 193.xxx.xxx.x : Online

which I'd like to clean up to get something like this:

Network 10.x.xx.xxx       : Online  
Network 10.x.xx.xxx       : Offline   
Network 10.x.xx.xxx       : Offline    
Network 10.x.xx.x         : Online    
Network 139.xxx.x.x       : Online  
Network 208.xx.xxx.xxx    : Online    
Network 193.xxx.xxx.x     : Online  
Network 193.xxx.xxx.xxx   : Offline
41

Use printf to format output (it's also more portable than echo). I would also store the real value of the colour escape sequences instead of storing them in a form that requires expansion by echo.

RED=$(tput setaf 1) GREEN=$(tput setaf 2) YELLOW=$(tput setaf 3)
NC=$(tput sgr0) 
online="${GREEN}online$NC" offline="${RED}offline$NC"

ping -c 1 "$hostname" > /dev/null 2>&1 && state=$online || state=$offline
printf 'Network %-15s: %s\n' "$hostname" "$state"

%-15s is a format specification that pads the strings with spaces on the right so as the length (in number of characters in zsh and fish and bytes in most other shells/printf) to be at least 15.

$ printf '|%-4s|\n' a ab abc abcd abcde
|a   |
|ab  |
|abc |
|abcd|
|abcde|
 printf '|%4s|\n' a ab abc abcd abcde
|   a|
|  ab|
| abc|
|abcd|
|abcde|

With truncation:

$ printf '|%.4s|\n' a ab abc abcd abcde
|a|
|ab|
|abc|
|abcd|
|abcd|
$ printf '|%4.4s|\n' a ab abc abcd abcde
|   a|
|  ab|
| abc|
|abcd|
|abcd|
$ printf '|%-4.4s|\n' a ab abc abcd abcde
|a   |
|ab  |
|abc |
|abcd|
|abcd|

Other utilities to format text in columns include POSIX expand:

printf 'Network %s\t: %s\n' "$hostname" "$state" | expand -t 30

(here expanding the TAB character (\t) with tab stops every 30 columns)

Or BSD column or POSIX pr:

printf 'Network %s\n: %s\n' "$hostname" "$state" | pr -at2

(here outputting on 2 36-column wide columns (see the -w option to change the page width from the default of 72)).

or BSD rs:

{
   while...
      printf 'Network %s\n: %s\n' "$hostname" "$state"
   done
} | rs -e 0 2

(like column won't start outputting until it has read all the input).

Or GNU columns:

printf 'Network %s\n: %s\n' "$hostname" "$state" | columns -w 25 -c 2

zsh also has some parameter expansion flags for string padding: ${(l:15:)hostname} for left padding and ${(r:15:)hostname} for right padding (with truncation). In prompt expansion (like in prompts or in print -P or as enabled in parameter expansions with the % flag), it also supports %F{green} for colour output, so you can do:

online='%F{green}online%f'
printf '%s\n' "Network ${(r:15:)hostname}: ${(%)online}"

Or:

print -rP "Network ${(r:15:)hostname}: $online"

Though the content of $hostname would then also be subject to prompt expansion, which would constitute a command injection vulnerability if the content of $hostname was not under your control (like in hostname='%<a[`reboot`]<')

34

Simply with column command:

yourscript.sh | column -t

The output:

Network  10.x.xx.xxx     :  Online
Network  10.x.xx.xxx     :  Offline
Network  10.x.xx.xxx     :  Offline
Network  10.x.xx.xxx     :  Offline
Network  10.x.xx.x       :  Online
Network  139.xxx.x.x     :  Online
Network  208.xx.xxx.xxx  :  Online
Network  193.xxx.xxx.x   :  Online
  • im sorry for stupid question, but where i should put that command? – pijaaa Oct 5 '17 at 8:18
  • @pijaaa, see my update, pipe with your script output – RomanPerekhrest Oct 5 '17 at 8:20
  • 9
    Note that column (a BSD command, also ported to Linux and found by default on some distributions, not to be confused with GNU columns) will need to read the whole input before it can start outputting something as it needs to compute the width of the columns based on the widest one. – Stéphane Chazelas Oct 5 '17 at 14:44
3

Update your script to insert a set number to \t (tabs) where you want to tab out to a column.

Output something simular to the following would give you the required alignment:

Network 10.x.xx.xxx\t: Online   
Network 10.x.xx.xxx\t: Offline   
Network 10.x.xx.xxx\t: Offline   
Network 10.x.xx.xxx\t: Offline   
Network 10.x.xx.x\t: Online   
Network 139.xxx.x.x\t: Online   
Network 208.xx.xxx.xxx\t: Online   
Network 193.xxx.xxx.x\t: Online
  • 3
    It would be worth adding a short example based on the script in the question... – Stephen Kitt Oct 5 '17 at 14:14
  • @StephenKitt ty Stephen, I was trying to figure out how to make it more than just one line, and this honestly didn't occur to me! – djsmiley2k Oct 5 '17 at 14:19
  • 3
    You'll notice that with the default tabstops every 8 columns, printf 'Network %s\t: Online\n' 8.8.8.8 192.168.122.123 doesn't align properly. You could work around that by using expand to expand the tabs with a different tab stop as shown in my answer. – Stéphane Chazelas Oct 5 '17 at 14:31
  • Please feel free to accept this as the answer then, by clicking the tick icon. – djsmiley2k Oct 9 '17 at 6:23
0

To display even better than @Roman

yourscript.sh | column -t -s $'\t'

Then add \t in each line to split it into column.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.