Hi, i wonder if someone can help me with this,

I am trying to get the results of top across multiple machines at the same time. I only care about the first process listed by 'top'. I can't figure out how to make this happen. I have got passwordless SSH, and have made the following script to extract the entry i care about from top.

#!/bin/sh
top | sed -n '
#Dont print all lines
/PID/ {
#if PID is found
n
#get the next line
p
#print it
}'

I dont know how to proceed to make it a) work across multiple machines simultaneously, if i ssh into another machine i get an error such as 'TERM environment variable not set', and if i run it in the background with & it just stops. b) make the output go onto the same line each time, instead of filling up my console with line after line of the same kind of output. The type of output i would like would be similar to top, just refreshing the output over the same lines.

Any kind of input towards helping me with either problem would be greatly appreciated!

Cheers,
Phil

Dani AI

Generated

Good progress in the thread: was right to point out using top in non-interactive/output mode, and correctly noted top can write to a file. ’s final script shows one workable approach, but it’s brittle (parsing top output with sed/tput) and can be simplified and made more robust.

Why the "TERM environment variable not set" and background issues happen

  • When you run a remote command over ssh without a pseudo-tty, some interactive programs expect a TERM and will error. You can either allocate a pty (ssh -t), set TERM on the remote side, or use a non-interactive snapshot mode (so no tty is required). Backgrounding an ssh that still needs stdin/tty will get stopped when the controlling terminal closes; use proper detaching or run non-interactive commands instead.

A more reliable pattern

  • Replace parsing of top with a single-shot, script-friendly command such as ps (its format options are much more predictable across shells and locales). Run that over ssh and tag each line with the hostname. For many hosts run the same command in parallel so results come back quickly.

Example (single host)

ssh remotehost "ps -eo user,pid,pcpu,pmem,time,comm --sort=-pcpu | sed -n '2p'"

Example (many hosts with GNU Parallel — prefixes each line with the host)

parallel -a hosts -j0 --tag ssh {} "ps -eo user,pid,pcpu,pmem,time,comm --sort=-pcpu | sed -n '2p'"

Practical tips

  • Force a stable locale (LANG=C) on the remote side if parsing text.
  • Don’t poll too frequently; add sleep/watch or use a monitoring agent for production.
  • For repeated queries enable SSH multiplexing (ControlMaster) to avoid connection overhead.
  • If you need in-place refresh over the same terminal area, use watch, tmux panes, or a small ncurses viewer rather than printing lines continuously.

Recommended Answers

All 3 Replies

I suggest you start top in batch mode and with the number of iterations set to 1. This way you take a a quick snapshot of things and save it to a file.

There is the -f option with top which will help you re-direct the output to a file and then you can apply sed on the output file.

Thanks for the tips guys, they pointed me in the right direction. If anybody else wants to do a similar thing, here's the script i came up with in the end:

#!/bin/bash
FILE=$HOME/mpd.hosts
#IP addresses of Hosts to check must be in that file

clear
echo -e 'HOST\tUSER\tVIRT\tRES\tS\t%CPU\t%MEM\tTIME+\tCOMMAND'
while [ "$response" != q ]
do
  thisIP=30
  tput cup 1 0
  echo "                                                                                "
  tput cup 1 0
  top -b -n 1 | sed -n ';/PID/ {;n;s/[^a-z]*\([a-z]*\)[^0-9a-z]*[0-9]*[^0-9a-z]*[0-9]*/'$thisIP'\t\1/p;}' |sed -e 's/[[:space:]][[:space:]]*/\t/g' -e 's/\([^[:space:]]*\t[^[:space:]]*\t[^[:space:]]*\t[^[:space:]]*\t\)[^[:space:]]*\t/\1/' -e 's/\([0-9]*:[0-9]*\)\.[0-9]*/\1/g'
  cnt=1
  cat $FILE | while read line
  do
    cnt=$(($cnt + 1))
    thisIP=$(echo $line | sed 's/[0-9]*\.[0-9]*\.[0-9]*\.//')
    tput cup $cnt 0
    echo "                                                                                "
    #Assumes an 80 character line
    tput cup $cnt 0
	  ssh -n -XC -p 22111 $line " top -b -n 1 "| sed -n ';/PID/ {;n;s/[^a-z]*\([a-z]*\)[^0-9a-z]*[0-9]*[^0-9a-z]*[0-9]*/'$thisIP'\t\1/p;}' |sed -e 's/[[:space:]][[:space:]]*/\t/g' -e 's/\([^[:space:]]*\t[^[:space:]]*\t[^[:space:]]*\t[^[:space:]]*\t\)[^[:space:]]*\t/\1/' -e 's/\([0-9]*:[0-9]*\)\.[0-9]*/\1/g'
  done
  maxCnt=$cnt
  echo "--------------------------------------------------------------------------------"
  echo "Type q to quit or anything else to refresh sooner"
  read -s -n1 -t 5 response
  #Will accept keypress, but wont do anything about it till it reaches here
done

The script also formats the output so it has the columns i wanted, as well as displaying the output from the current machine. It assumes that the file $HOME/mpd.hosts contains a list of IP addresses, 1 per line, that you can ssh to without a password.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.