Get CPU and Memory Info In Different HPUX unix Servers - linux

I am trying to make a bash script to get CPU and Memory information in different Unix servers and pipe them into a single text file in the local server.
The script returns something (result), but the result was not accurate when I check each of the servers CPU and Memory information manually. There might be some error in the scripts since the CPU and Memory commands are correct.
Here is the command to get CPU information in Unix (HPUX) :
machinfo | grep CPUs | awk '{print $5}'
And the result will be :
4
And here is the command to get Memory information in Unix (HPUX) :
machinfo | grep Memory | awk '{print $3}'
And the result will be :
4090
It shows that the commands are correct. Let's go into the full scripts.
#!/bin/ksh
SERVERS='
xxx.xxx.xxx.xxx
xxx.xxx.xxx.xxx'
cpu=$(machinfo | grep CPUs | awk '{print $5}')
mem=$(machinfo | grep Memory | awk '{print $3}')
print "SERVER" "CPU" "RAM (MB)";
for i in $SERVERS
do
ssh -n $i 2>&1 '$cpu | $mem'
print $cpu $mem
done
When the full scripts run, the result will be:
SERVER CPU RAM (MB)
s24bf011 2 4090
s24bf012 2 4090
s24bf013 2 4090
s24bf014 2 4090
s24bf016 2 4090
S24BF104 2 4090
S24BF105 2 4090
10.14.24.158 2 4090
S29BF200 2 4090
S02BF131 2 4090
S02BF104 2 4090
S24BF071 2 4090
S24BF165 2 4090
10.14.24.17 2 4090
Every server has a different CPU and RAM. How come they were all the same?
Error in SSHing?

Your script has multiple problems.
'$cpu | $mem'
is just a literal string. If you want to interpolate the values of $cpu and $mem, you need to use double quotes instead of single.
But
"$cpu | $mem"
will basically discard the output from $cpu because you are piping it to $mem which is ignoring its standard input. The proper way to run two independent commands is to put a semicolon between them, not a pipe. The function of the pipe is to take the standard output from the command before the pipe and redirect it as standard input into the command after the pipe.
But of course, the variables you declared do not contain the scripts; they contain the output of the Awk scripts, which you ran locally when you put them in process substitutions.
You should have received error messages about all of this; what happened to them?
Anyway, you can simplify processing enormously by refactoring this to just run a single command, anyway.
print "SERVER" "CPU" "RAM (MB)";
for i in $SERVERS
do
ssh -n "$i" "machinfo |
awk -v s='$i' '/CPUs/ { c=\$5 } /Memory/ { m=\$3 }
END { print s, c, m }'"
done
Here, I use double quotes around the remote command so that I can interpolate the server name into the Awk variable s. The internal single quotes inside the double quotes do not have any significance to the local shell, i.e. they do not prevent the local shell from replacing the dollar signs, so we need to protect the dollar signs by backslash-escaping them.
But unless your local Awk is crippled or something, it doesn't make sense to run Awk remotely.
for i in $SERVERS
do
ssh -n "$i" machinfo |
awk -v s="$i" '/CPUs/ { c=$5 } /Memory/ { m=$3 }
END { print s, c, m }'
done
Putting stuff which isn't variable and which is only used once into a variable is just silly, and sometimes problematic (see http://mywiki.wooledge.org/BashFAQ/050).

Related

Set part of grep to variable

mysqladmin proc status | grep "Threads"
Output:
Uptime: 2304 Threads: 14 Questions: 2652099 Slow queries: 0 Opens: 48791 Flush tables: 3 Open tables: 4000 Queries per second avg: 1151.08
I would like to set it so $mysqlthread would output 14 after running echo $mysqlthread
Probably the easiest way is with Perl instead of grep.
mysqladmin proc status | perl -nle'/Threads: (\d+)/ && print $1'
perl -n means "go through each line of input".
perl -l means "print a \n at the end of every print"
perl -e means "here is my program"
/Threads: (\d+)/ means "match Threads: followed by one or more digits. And print $1 means "print the digits I found as denoted by the parentheses around \d+.
Using grep
$ mysqlthread=$(mysqladmin proc status | grep -Po 'Threads: \K\d+')
$ echo "$mysqlthread"
14
There are many ways to solve this. This is one:
mysqladmin proc status | grep "Threads" | tr -s ' ' | cut -d' ' -f4
The tr command with flag -s is used to translate all multiple consecutive spaces into a single space. Then, cut command return the 4th field using a single space as delimiter.
The advantage of piping commands is that one can make this process interactively. And whenever you aren't sure which flag to use, the manual pages are there to help: man grep, man tr, man cut, etc.
Add awk to split the output,
mysqlthread=$(mysqladmin proc status | grep "Threads" | awk '{print $4}')

Net Usage (%) of a Process in Linux

I'm trying to build a script in Linux (Debian 10) that shows the net usage (%) of a process passed as an argument.
This is the code, but there isn't any output:
ProcessName=$1
(nethogs -t ens33 | awk '/$ProcessName/{print $3}') &> output.txt
While using tracemode nethogs -t, first field of output is program and it can consists of irregular number of arguments.
In case of brave:
/usr/lib/brave-bin/brave --type=utility --utility-sub-type=network.mojom.NetworkService --field-trial-handle=18208005703828410459,4915436466583499460,131072 --enable-features=AutoupgradeMixedContent,DnsOverHttps,LegacyTLSEnforced,PasswordImport,PrefetchPrivacyChanges,ReducedReferrerGranularity,SafetyTip,WebUIDarkMode --disable-features=AutofillEnableAccountWalletStorage,AutofillServerCommunication,DirectSockets,EnableProfilePickerOnStartup,IdleDetection,LangClientHintHeader,NetworkTimeServiceQuerying,NotificationTriggers,SafeBrowsingEnhancedProtection,SafeBrowsingEnhancedProtectionMessageInInterstitials,SharingQRCodeGenerator,SignedExchangePrefetchCacheForNavigations,SignedExchangeSubresourcePrefetch,SubresourceWebBundles,TabHoverCards,TextFragmentAnchor,WebOTP --lang=en-US --service-sandbox-type=none --shared-files=v8_context_snapshot_data:100/930/1000 0.0554687 0.0554687
so $3 will no longer be as expected, you need to get last column of output using $(NF) as follow:
... | awk /$ProcessName/'{print $(NF)}'
for second last column:
... | awk /$ProcessName/'{print $(NF - 1)}'
What I'm doing wrong?
What you're doing wrong is single-quoting $ProcessName while wanting this to be parameter-expanded. To get the expansion, just don't quote there, e. g.:
… awk /$ProcessName/'{print $3}' …

Using LINUX top command to compute used memory percentage

I am writing the top command output to a text file.
I am trying to write a simple bash script to calculate the percentage of used memory and send an
email if the memory used percentage exceeds, say 90%.
Here is the bash script I have thus far.
#!/bin/bash
top -n 1 -b | grep "Mem" > /home/modadm/top-output.txt
MAXMEM=/home/modadm/top-output.txt | grep "Mem" | cut -c 7-14
USEDMEM=/home/modadm/top-output.txt | grep "Mem" | cut -c 25-31
$USEDPCT='echo $USEDMEM / $MAXMEM * 100 | bc'
$USEDPCT | mail -s "Test Email from MOD Server" test#test.com
When I save and execute the script, I get the error "No such file or directory":
-bash-3.2$ ./memcheck.sh
./memcheck.sh: line 4: =echo $USEDMEM / $MAXMEM * 100 | bc: No such file or directory
Null message body; hope that's ok
-bash-3.2$
Can someone assist? I am a newbie to bash scripting and this is my first script.
Thank you
I will not repeat the content of the other answers; instead I will question the wisdom of parsing the output of top, when all you need is information on the system memory usage.
The output of top is intended for humans and also contains a lot of per-process information that is both unneeded and expensive to produce. The output of free is far more suitable for this particular use.
Secondly, judging by the calculations in your script, you do not seem to understand the way system memory usage is measured on Linux and other Unix-like systems. Contrary to the other OS, the used memory size contains the memory used for disk caches and other buffers. On any system that has been up for some time the free memory tends towards zero - unused memory is wasted memory.
A first step towards finding out the amount of memory used by processes would be to subtract the amount of memory used for buffers from the used memory size. But even that would not be enough on a modern system - even free and top get it wrong to a degree, as mentioned in this older answer of mine.
You have a few problems here.
First, this doesn't do what you want it to do.
USEDMEM=/home/modadm/top-output.txt | grep "Mem" | cut -c 25-31
You can't pipe a filename into a command. You actually want to pipe the contents of the file into the command. You can do that with 'cat'. However, grep is actually designed to search within a file so you can do
USEDMEM=$(grep "Mem" /home/modadm/top-output.txt | cut -c 25-31)
Note that $(cmd) is how you execute a command in a subshell. i.e., you can run some commands to compute the value of a variable in your script. You can also use `cmd` (backticks; usually on the tilde key) but that syntax is less clear.
Again, you probably want to calculate this result in a subshell. Also, don't use $ when assigning to variables.
$USEDPCT='echo $USEDMEM / $MAXMEM * 100 | bc'
This can be rewritten as
USEDPCT=$(echo "scale=3; $USEDMEM / $MAXMEM * 100" | bc)
Finally, you want to pipe the contents of the variable into the mail program. The pipe is expecting a program to be on the left hand side. You do this by echo'ing the value of the variable into the pipe.
echo "$USEDPCT" | mail -s "Test Email from MOD Server" test#test.com
To put everything back together:
#!/bin/bash
top -n 1 -b | grep "Mem" > /home/modadm/top-output.txt
MAXMEM=$(grep "Mem" /home/modadm/top-output.txt | cut -c 7-14)
USEDMEM=$(grep "Mem" /home/modadm/top-output.txt | cut -c 25-31)
USEDPCT=$(echo "$USEDMEM / $MAXMEM * 100" | bc -l)
echo "$USEDPCT" | mail -s "Test Email from MOD Server" test#test.com
Others have pointed out problems with your code, but there are much easier options for this, namely not parsing top output at all. Use /proc/meminfo, and awk - you won't need a temporary file.
$ awk '/MemTotal:/{total=$2} \
/MemFree:/{free=$2} \
END{ \
print "Free mem percent: "(free*100/total); \
print "Used mem percent: "((total-free)*100/total) \
}' /proc/meminfo
Free mem percent: 87.7348
Used mem percent: 12.2652
Pipe that to mail or whatever you want.
Try the following script.
#! /bin/bash
memusage=`top -n 1 -b | grep "Mem"`
MAXMEM=`echo $memusage | cut -d" " -f2 | awk '{print substr($0,1,length($0)-1)}'`
USEDMEM=`echo $memusage | cut -d" " -f4 | awk '{print substr($0,1,length($0)-1)}'`
USEDMEM1=`expr $USEDMEM \* 100`
PERCENTAGE=`expr $USEDMEM1 / $MAXMEM`%
echo $PERCENTAGE | mail -s "Test Email" test#test.com
I have corrected your syntax errors. Pl. note the use of command substitution,
like you have written
MAXMEM=/home/modadm/top-output.txt | grep "Mem" | cut -c 7-14.
This is wrong, you need to write
grep "Mem" /home/modadm/top-output.txt | cut -c 7-14
and then enclose it within backquotes(the key at the lefthand side over tab key) to assign final value to a variable.
Also you have written,
$USEDPCT='echo $USEDMEM / $MAXMEM * 100 | bc'
The dollar sign is used wrongly. $ should be used when you are using the value of
a variable.The quotes should be ` (back quote) and not '(single quote). Backquote means the command will be substituted with the output of the command.
Also for floating point bc needs a scale to be set.
Pl. see the modified code. Hope this helps. Pl. note I have not checked the functionality of the mail command that if it is sending mail or not.
top -n 1 -b | grep "Mem" > /home/modadm/top-output.txt
MAXMEM=`grep "Mem" /home/modadm/top-output.txt | cut -c 7-14`
USEDMEM=`grep "Mem" /home/modadm/top-output.txt | cut -c 25-31`
USEDPCT=`echo "scale=2; $USEDMEM / $MAXMEM * 100" | bc `
echo $USEDPCT | mail -s "Test Email from MOD Server" test#test.com

Simpler way of extracting text from file

I've put together a batch script to generate panoramas using the command line tools used by Hugin. One interesting thing about several of those tools is they allow multi-core usage, but this option has to be flagged within the command.
What I've come up with so far:
#get the last fields of each line in the file, initialize the line counter
results=$(more /proc/cpuinfo | awk '{print ($NF)}')
count=0
#loop through the results till the 12th line for cpu core count
for result in $results; do
if [ $count == 12 ]; then
echo "Core Count: $result"
fi
count=$((count+1))
done
Is there a simpler way to do this?
result=$(awk 'NR==12{print $NF}' /proc/cpuinfo)
To answer your question about getting the first/last so many lines, you could use head and tail,e.g. :
cat /proc/cpuinfo | awk '{print ($NF)}' | head -12 | tail -1
But instead of searching for the 12th line, how about searching semantically for any line containing cores. For example, some machines may have multiple cores, so you may want to sum the results:
cat /proc/cpuinfo | grep "cores" | awk '{s+=$NF} END {print s}'
count=$(getconf _NPROCESSORS_ONLN)
see getconf(1) and sysconf(3) constants.
According to the Linux manpage, _SC_NPROCESSORS_ONLN "may not be standard". My guess is this requires glibc or even a Linux system specifically. If that doesn't work, I'd probably take looking at /sys/class/cpuid (perhaps there's something better?) over parsing /proc/cpuinfo. None of the above are completely portable.
There are many ways:
head -n 12 /proc/cpuinfo | tail -1 | awk -F: '{print $2}'
grep 'cpu cores' /proc/cpuinfo | head -1 | awk -F: '{print $2}'
and so on.
But I must note that you take only the information from the first section of /proc/cpuinfo and I am not sure that that is what you need.
And if the cpuinfo changes its format ;) ? Maybe something like this will be better:
cat /proc/cpuinfo|sed -n 's/cpu cores\s\+:\s\+\(.*\)/\1/p'|tail -n 1
And make sure to sum the cores. Mine has got like 12 or 16 of them ;)
unsure what you are trying to do and why what ormaaj said above wouldn't wouldn't work either. my instinct based on your description would have been much simpler along the lines of.
grep processor /proc/cpuinfo | wc -l

How to get the total physical memory in Bash to assign it to a variable?

How can I get the total physical memory in bytes of my Linux PC?
I need to assign it to a bash script variable.
grep MemTotal /proc/meminfo | awk '{print $2}'
The returned number is in KB
phymem=$(awk -F":" '$1~/MemTotal/{print $2}' /proc/meminfo )
or using free
phymem=$(LANG=C free|awk '/^Mem:/{print $2}')
or using shell
#!/bin/bash
while IFS=":" read -r a b
do
case "$a" in
MemTotal*) phymem="$b"
esac
done <"/proc/meminfo"
echo $phymem
I came up with this one under the assumption, that the physical memory will be the first number in free's output:
free -m | grep -oP '\d+' | head -n 1
This allows you to configure free to output the unit you want (-m, -g, ...) and it is independent of the system language (other answers depend on the "Mem:" string in free's output which may change based on the language).
How about
var=$(free | awk '/^Mem:/{print $2}')
I'll try to make this answer self explanatory, just keep up with me.
To get the description of memory, you can use the free utility :
free -t
Output (in KB):
total used free shared buff/cache available
Mem: 8035900 3785568 324984 643936 3925348 3301908
Swap: 3906556 271872 3634684
Total: 11942456 4057440 3959668
To extract all of these values from this output in a single column :
free -t | grep -oP '\d+'
Output (in KB):
8035900
3866244
266928
650348
3902728
3214792
3906556
292608
3613948
11942456
4158852
3880876
Note : Minute difference can be there in values, which doesn't matter most of the times.
If you just want to get the total physical memory (mem+swap), it is the 10th value in above output :
free -t | grep -oP '\d+' | sed '10!d'
Output (on my PC):
11942456
Note: All the above outputs are in Kilo Bytes. If you want in Mega Bytes or Giga Bytes just append -m or -g after -t in
above free commands respectively.
For Example :
free -t -g | grep -oP '\d+' | sed '10!d'
Output (in Giga Bytes on my PC) :
11
Silly inline python version, which looks overly complicated, but is actually kind of useful.
freemem=$(echo -e 'import re\nmatched=re.search(r"^MemTotal:\s+(\d+)",open("/proc/meminfo").read())\nprint(int(matched.groups()[0])/(1024.**2))' | python)
It returns the memory in GB.
If someone need a human readable:
var=$(free -h | awk '/^Mem:/{print $2}')
result:
1.9G

Resources