Unexpected Argument expr & MemTotal - bash

Attempting to get this little bash script working and I am currently receiving this error:
Not sure where my syntax issue is.
expr: syntax error: unexpected argument ‘32489356’
Your System RAM is: $RAM_GB GB and that meets the minimum requirements for Docker Desktop.
#!/bin/bash
CURRENT_TIME="$(date +"%x %r %Z")"
TIMESTAMP="Generated $CURRENT_TIME, by $USER"
echo $TIMESTAMP
check_ram () {
RAM_KB=$(grep MemTotal /proc/meminfo)
RAM_GB=$(expr $RAM_KB / 1000000)
if ($RAM_GB > 4); then
echo 'Your System RAM is: $RAM_GB GB and that meets the minimum requirements for Docker Desktop.'
else
echo 'Your computer does not meet the minimum RAM requirements.'
exit 0
fi
return
}

Here is a fix
#!/bin/bash
CURRENT_TIME="$(date +"%x %r %Z")"
TIMESTAMP="Generated $CURRENT_TIME, by $USER"
echo $TIMESTAMP
check_ram () {
RAM_KB=$(grep MemTotal /proc/meminfo | awk '{print $2}')
RAM_GB=$(expr $RAM_KB / 1000000)
if [ $RAM_GB -gt 4 ]; then
echo "Your System RAM is: $RAM_GB GB and that meets the minimum requirements for Docker Desktop."
else
echo "Your computer does not meet the minimum RAM requirements."
exit 0
fi
return
}

Related

how to run multiple commands on a remote linux server using bash script

I am currently writing the following script that logs into a remote server and runs couple of commands to verify the performance of the server and prints a message based on the output of those commands .But the ssh doesn't work and returns the stats of the server that hosts the script instead .
Script
#!/bin/bash
#######################
#Function to add hosts to the array
#the following function takes the ip addresses provided while the script is run and stores them in an array
#######################
Host_storing_func () {
HOST_array=()
for i in $# ;do
HOST_array+=(${i});
done
#echo ${HOST_array[*]}
}
#######################
#Calling above function
#######################
Host_storing_func "$#"
############################################################
#Collect Stats of Ping,memory,iowait time test function
############################################################
b=`expr ${#HOST_array[*]} - 1 `
for i in `seq 0 $b` ;do
sshpass -f /root/scripts/passwordFile.txt /usr/bin/ssh student35#${HOST_array[${i}]} << HERE
echo `hostname`
iowaittm=`sar 2 2|awk '/^Average/{print $5};'`
if [ $iowaittm > 10 ];then
echo "IO ==> BAD"
else
echo "IO ==> GOOD"
fi
memoryy=`free -m |grep Swap|awk '{if($2 == 0) print 0;else print (($4 / $2 ) * 100)}'`
if [ ${memoryy} < '10' ] ;then
echo "memory ==> good"
elif [[ "${memory}" -ge 0 ]] && [[ "${memory}" -le 10 ]];then
echo "No Swap"
else
echo "memory ==> bad"`enter code here`
fi
ping -w2 -c2 `hostname` | grep "packet loss"|awk -F, '{print $3}'|awk -F% '{print $1}'|sed 's/^ *//'|awk '{if ($1 == 0) print "Yes" ;else print "No"}'
HERE
done
Output : oc5610517603.XXX.com is the name of the source server
[root#oc5610517603 scripts]# ./big_exercise.sh 9.XXX.XXX.XXX 9.XXX.XXX.XXX
Pseudo-terminal will not be allocated because stdin is not a terminal.
oc5610517603.XXX.com
IO ==> GOOD
No Swap
ping: oc5610517603.ibm.com: Name or service not known
Pseudo-terminal will not be allocated because stdin is not a terminal.
oc5610517603.XXX.com
IO ==> GOOD
No Swap
ping: oc5610517603.XXX.com: Name or service not known
thanks for checking the script , I figured out a way to solve the problem
It is the sshpass command that is causing issue , you just have to put the opening HERE in single quotes if you want to use variables with in the HEREdoc but if the variables are calculated before ssh then you don't have to put opening HERE in single quotes
sshpass -f /root/scripts/passwordFile.txt /usr/bin/ssh -T student35#${i} << 'HERE'
after I changed the sshpass command as above my script worked
I have modified your script a bit.
As suggested by #chepner, I am not using the Host_storing_func.
Heredocs for sshpaas are somewhat tricky. You have to escape every back-tick and $ sign in the heredoc.
Notice the - before the heredoc start, it allows you to indent the heredoc body. Also, try to avoid back-ticks when you can. use $(command) instead.
Hope it helps.
#!/bin/bash
#######################
#Function to add hosts to the array
#the following function takes the ip addresses provided while the script is run and stores them in an array
#######################
array=( "$#" )
user="student35"
############################################################
#Collect Stats of Ping,memory,iowait time test function
############################################################
for host in ${array[#]}; do
sshpass -f /root/scripts/passwordFile.txt /usr/bin/ssh -l ${user} ${host} <<-HERE
thishost=\$(hostname)
echo "Current Host -> \$thishost";
iowaittm=\`sar 2 2|awk '/^Average/{print \$5}'\`
if [ \$iowaittm > 10 ]; then
echo "IO ==> BAD"
else
echo "IO ==> GOOD"
fi
memory=\$(free -m | grep Swap | awk '{if(\$2 == 0) print 0;else print ((\$4 / \$2 ) * 100)}')
if [ \${memory} < '10' ] ;then
echo "memory ==> good"
elif [[ "\${memory}" -ge 0 ]] && [[ "\${memory}" -le 10 ]]; then
echo "No Swap"
else
echo "memory ==> bad"\`enter code here\`
fi
ping -w2 -c2 \`hostname\` | grep "packet loss"|awk -F, '{print \$3}'|awk -F% '{print \$1}'|sed 's/^ *//'|awk '{if (\$1 == 0) print "Yes" ;else print "No"}'
HERE
done

BASH variable not populating

Got it working, here is the code: https://github.com/MNFaust/Linux_Memory_Mining/blob/master/subScripts/gdb_mine.sh
THANK YOU!
I am working on a subscript that is being called in a program to grab data from Memory Addresses and I am trying to automate the Stack and Heap mem dumps with GDB. Everything is working except for the memory address variable calls. Can someone please let me know if they see where I am going wrong with this:
#!/bin/bash
#========================================
#GDB processes: Gaining data
#By: Joshua Faust
#========================================
echo '------------------------------'
echo 'Process ID Data Required: '
echo '------------------------------'
echo -n "What is the PID you are inquiring about: "; read PID
awk '{print $1,$6}' /proc/$PID/maps > "${PID}_maps"
# Grab the heap memory address for the PID
heapAddress=`cat /proc/$PID/maps | grep heap | awk '{print $1}'` #Grab the HEAP address in memory
heapAddressRemove=${heapAddress/-/" 0x"} #reove the -, add 0x to denote a hex address for GDB
heapAddressFinal= echo "$heapAddressRemove" | awk '$0="0x"$0' #adds a 0x to the from of the mem address to denote a hex address
# Grab the stack memory address for the PID
stackAddress=`cat /proc/$PID/maps | grep stack | awk '{print $1}'` #Grab the STASCK address in memory
stackAddressRemove=${stackAddress/-/" 0x"} #remove the - in the memory address for GDB
stackAddressFinal= echo "$stackAddressRemove" | awk '$0="0x"$0' # adds a 0x to the front of the memory address to denote a hex addess
clear #Clear data on screen
echo '---------------------------'
echo 'Starting Mining Processes '
echo '---------------------------'
#
# Ask user if you would like to view the memory map segments of the processes they chose.
#
echo -n "Would you like to see PID $PID memory map? (y or n) "; read pidAnswer
if [ $pidAnswer == "y" ] || [ $pidAnswer == "Y" ]
then
echo
cat "${PID}_maps"
else
echo 'continuing to GDB session...'
echo
fi
#
# Start of the GDB session:
#
echo -n "Are you ready to start a GDB session on $PID? (y or n) "; read mineAnswer
if [ $mineAnswer == "y" ] || [ $mineAnswer == "Y" ]
then
echo '--------------------------------------------------------------------------------'
echo ' Getting Register Information '
echo ''
echo 'To dump: dump [memory,binary,tekhex, verilog] FileLocation Memory Segment Range '
echo 'To quit: quit'
echo Heap Address: $heapAddressFinal
echo Stack Address: $stackAddressFinal
echo '--------------------------------------------------------------------------------'
echo
echo -n 'Would you like to dump the stack or the heap? '; read dump
if [ $dump == "heap" ] || [ $dump == "Heap" ]
then
gdb --pid $PID -ex 'dump memory HeapDump.hex $heapAddressFinal' # to add another command -ex command
echo 'Data dumped to HeapDump.hex'
elif [ $dump == "stack" ] || [ $dump == "Stack" ]
then
gdb --pid $PID -ex 'dump memory StackDump.hex $stackAddressFinal'
echo 'Data dumped to StackDump.hex'
fi
else
echo
echo 'closing program....'
exit 1
fi
rm -rf PID.txt #remove the temp file created to hold the PID
Here is the output where I am having issues. When I echo and call the variable stackAddressFinal and heapAddressFinal, they do not populate on console. However, in a test script I build they do.
Are you ready to start a GDB session on 21505? (y or n) y
--------------------------------------------------------------------------------
Getting Register Information
To dump: dump [memory,binary,tekhex, verilog] FileLocation Memory Segment Range
To quit: quit
Heap Address:
Stack Address:
--------------------------------------------------------------------------------
Would you like to dump the stack or the heap?
You need to add quotes, like heapAddressFinal=`echo "$heapAddressRemove" | awk '$0="0x"$0'`. Hope this helps.

Collecting data from a UNIX program with Bash Redirection

I am attempting to write a script that outputs a CSV file (specified by the user), from the temperature value given by the acpi program. Each data entry is appended to the CSV file, every second (for now).
I have two issues that need to be resolved in my script:
To fix the errors in the script (such as the file access error on line 14), and to allow the user to specify the time delay.
Here's the bash script:
#!/bin/bash
# This script monitors the CPU temperature (in degrees C) over time, and
# records the data to a CSV file.
# Written by Ben Cottrell
function start_log()
{
touch "$output_csv"
if hash acpi 2>/dev/null; then
echo -e "time,temperature\n" > "$output_csv"
while (true); do
sleep 1
echo -e "$(date +%T),$(acpi -t | awk '{print $4}')\n" >> "$output_csv"
done
else
echo "Error: acpi is not installed. Please execute \"sudo apt-get install acpi, before running this script.\""
fi
}
if [ "$1" ]; then
local output_csv = $1
start_log
else
echo -e "Error: No filename specified.\n"
fi
echo -e "\n"
Here's a rewrite with the worst errors and idiom violations fixed.
#!/bin/bash
function start_log()
{
local output_csv=$1
local delay=$2
if hash acpi 2>/dev/null; then
echo "time,temperature" > "$output_csv"
while true; do
sleep "$delay"
echo "$(date +%T),$(acpi -t | awk '{print $4}')"
done >>"$output_csv"
else
cat <<________error >&2
$0: Error: acpi is not installed.
Please execute \"sudo apt-get install acpi\" before running this script.
________error
exit 2
fi
}
delay=1 # default to 1 sec delay
while true; do
case $1 in
-t) shift; delay=$1; shift;; # Maybe validate the value of $delay
-*) echo "$0: Unknown option: '$1'" >&2; exit 1;;
*) break;;
esac
done
if [ "$1" ]; then
start_log "$1" "$delay"
else
echo "$0: Error: No filename specified." >&2
exit 1
fi
Including the program name in error messages is useful when it is being invoked from another script, which might get invoked from another script, etc.
Notice how the redirection is only done once, after the loop, instead of repeatedly inside the main loop.
Notice also how the function receives its parameters from the caller, instead of pulling in global variables.
Hand-crafting the option parsing is hardly more complex than doing it "properly" with getopts for simple processing.
Try this.
#!/bin/bash
# This script monitors the CPU temperature (in degrees C) over time, and
# records the data to a CSV file.
# Written by Ben Cottrell
function start_log()
{
touch "$output_csv"
read -p 'Enter the time interval for collecting data in seconds: ' t
if hash acpi 2>/dev/null; then
echo -e "time,temperature\n" > "$output_csv"
while (true); do
sleep $t
echo -e "$(date +%T),$(acpi -t | awk '{print $4}')\n" >> "$output_csv"
done
else
echo "Error: acpi is not installed. Please execute \"sudo apt-get install acpi, before running this script.\""
fi
}
if [ -n "$1" ]; then
local output_csv = $1
start_log
else
echo -e "Error: No filename specified.\n"
fi
echo -e "\n"

Script to Format and Mount all available instance store devices

Amazon provides instance store for EC2 instances. If you use your own AMI, these are not formatted or mounted automatically for you. You need to manually format and mount them.
The available devices are listed here and vary based on type of instance. For example an m1.small will have different available instance store devices than c1.xlarge.
I'm looking for a script which
Detects what the instance type is. Perhaps by using
curl -s http://169.254.169.254/latest/meta-data/instance-type
Formats and mounts all devices which are available for that instance type but have not yet been formatted/mounted.
Possible? Done it? Have it?
So, here is what I built for this.
#!/bin/bash
# This script formats and mounts all available Instance Store devices
##### Variables
devices=( )
##### Functions
function add_device
{
devices=( "${devices[#]}" $1 )
}
function check_device
{
if [ -e /dev/$1 ]; then
add_device $1
fi
}
function check_devices
{
check_device sda2
check_device sda3
check_device sdb
check_device sdc
check_device sdd
check_device sde
}
function print_devices
{
for device in "${devices[#]}"
do
echo Found device $device
done
}
function do_mount
{
echo Mounting device $1 on $2
fdisk $1 << EOF
n
p
1
w
EOF
# format!
mkfs -t xfs -f $1
mkdir $2
mount $1 $2
echo "$1 $2 xfs defaults 0 0" >> /etc/fstab
}
function mount_devices
{
for (( i = 0 ; i < ${#devices[#]} ; i++ ))
do
mountTarget=/mnt
if [ $i -gt 0 ]; then
mountTarget=/mnt$(($i+1))
fi
do_mount /dev/${devices[$i]} $mountTarget
done
}
##### Main
check_devices
print_devices
mount_devices
#!/bin/bash
#SETUP RAID0
checkAllDevices()
{
devicemount=/ephemeral
logicalname=/dev/md0
deviceslist=( '/dev/xvdb' '/dev/xvdc' '/dev/xvdd' '/dev/xvde' )
for device in ${deviceslist[#]}; do
if ([ -b $device ]) then
aDevices=( "${aDevices[#]}" $device )
fi
done
if [ "${#aDevices[#]}" -gt '1' ];then
yes | mdadm --create $logicalname --level=0 -c256 --raid-devices=${#aDevices[#]} ${aDevices[#]}
echo \'DEVICE ${aDevices[#]}\' > /etc/mdadm.conf
mdadm --detail --scan >> /etc/mdadm.conf
blockdev --setra 65536 $logicalname
mkfs.xfs -f $logicalname > /dev/null
mkdir -p $devicemount
mount -t xfs -o noatime $logicalname $devicemount
if [ ! -f /etc/fstab.backup ]; then
cp -rP /etc/fstab /etc/fstab.backup
echo "$logicalname $devicemount xfs defaults 0 0" >> /etc/fstab
fi
else
echo "Required more than one devices"
fi
}
#MAIN FUNCTION
aDevices=()
checkAllDevices

Shell Script Syntax Error: Unexpected End of File [duplicate]

This question already has answers here:
Bash syntax error: unexpected end of file
(21 answers)
Closed 3 years ago.
In the following script I get an error:
syntax error: unexpected end of file
What is this error how can I resove it? It is pointing at the line whee the function is called.
#!/bin/sh
expected_diskusage="264"
expected_dbconn="25"
expected_httpdconn="20"
expected_cpuusage="95"
#expected_fd="100"
httpdconn=`ps -ef|grep -i httpd|grep -v grep|wc -l` #httpd connections
cpu_usage=`ps aux|awk 'NR > 0 { s +=$3 }; END {print s}'`
disk_usage=`df -h|awk {'print $2'}|head -n3|awk 'NF{s=$0}END{print s}'`
#db_connections=`mysql -uroot -pexxxxxx -s -N -e "show processlist"|wc -l`
db_connections=6
cld_alert()
{
nwconn=$1
cpu_usage=$2
disk_usage=$3
db_connections=$4
message=$5
`touch /tmp/alert.txt && > /tmp/alert.txt`
date=`date`
echo -e "$date\n" > /tmp/alert.txt
echo -e "$message" >> /tmp/alert.txt
path="/proc/$httpd/fd/";
cd $path
tfd=`ls -l|wc -l`;
sfd=`ls -ltr|grep sock|wc -l`;
echo "Total fds: $tfd" >> /tmp/alert.txt
echo "Socket fds: $sfd" >> /tmp/alert.txt
echo "Other fds: $[$tfd - $sfd]" >> /tmp/alert.txt
freememory=`vmstat | awk '{if (NR == 3) print "Free Memory:"\$4}'`;
echo "Free memory :$freememory" >> /tmp/alert.txt
Bufferedmemory=`vmstat | awk '{if (NR == 3) print "Buffered Memory:"\$5}'`;
echo "Buffered memory $Bufferedmemory" >> /tmp/alert.txt
CacheMemory=`vmstat | awk '{if (NR == 3) print "Cache Memory:"\$6}'`;
echo "Cache memory : $CacheMemory" >> /tmp/alert.txt
sshconn=`netstat -an|grep 22|wc -l` #ssh connections
httpsconn=`netstat -an|grep 443|wc -l` #https connections
wwwconn=`netstat -an|grep 80|wc -l` #www connections
echo "Disk usage is $disk_usage" >> /tmp/alert.txt
echo "DB connections $db_connections" >> /tmp/alert.txt
echo "Network connections $nwconn" >> /tmp/alert.txt
echo "CPU Usage: $cpu_usage" >> /tmp/alert.txt
topsnapshot=`top -n 1 -b`
echo "===========================TOP COMMAND SNAPSHOT====================================================";
echo "$topsnapshot" >> /tmp/alert.txt
echo"==================PS COMMAND SNAPSHOT=============================================================="
entireprocesslist=`ps -ef`
echo "$entireprocesslist" >> /tmp/alert.txt
echo Hello hi"";
}
message=""
if [ ${disk_usage%?} -le $expected_diskusage ] ##{x%?} Removes last character
then
echo "disk usage exceeded";
message="Disk usage limit exceeded \nCurrent disk usage is $disk_usage\nConfigured disk usage is $expected_diskusage\n\n\n\n\n";
#Checking for CPU usage
if [ $cpu_usage -ge $expected_cpuusage] ##{x%?}
then
echo "CPU usage exceeded";
if [ $message -ne "" ]
then
message="$message\n\nCPU usage exceeded configured usage limit \nCurrent CPU usage is $cpu_usage\nConfigured CPU usage is $expected_cpuusage\n\n\n\n\n";
else
message="CPU usage exceeded configured usage limit \nCurrent CPU usage is $cpu_usage\nConfigured CPU usage is $expected_cpuusage\n\n\n\n\n";
fi ;
fi
#Checking for httpd connections
if [ $httpdconn -ge $expected_httpdconn] ##{x%?}
then
echo "HTTPD connections exceeded";
if [ $message -ne "" ]
then
message="$message\n\nHTTPD connections exceeded configured usage limit \nCurrent HTTPD connections is $httpdconn\nConfigured HTTPD connection is $expected_httpdconn";
else
message="HTTPD connections exceeded configured usage limit \nCurrent HTTPD connections is $httpdconn\nConfigured HTTPD connection is $expected_httpdconn";
fi ;
fi ;
message="$message\n\n\n\n\n";
value=$(cld_alert $message $httpdconn $cpu_usage $disk_usage $db_connections)
Edit: Note that the original post has been edited since this answer was written and has been reformatted. You should look at the history to see the original formatting to understand the context for this answer.
This error occurs often when you have mismatched structure - that is, you do not have matching double quotes, matching single quotes, have not closed a control structure such as a missing fi with an if, or a missing done with a for.
The best way to spot these is to use correct indentation, which will show you where you have a broken control structure, and syntax highlighting, which will show you where quotes are not matched.
In this particular case, I can see you are missing a fi. In the latter part of your code, you have 5 ifs and 4 fis. However you also have a number of other problems - your backquoted touch /tmp/alert.txt... command is syntactically invalid, and you need a space before the closing bracket of an if test.
Clean up your code, and errors start to stand out.
in my case the issue was in the EOL Conversion. (End Of Line).
i created the file on windows and only after i converted the EOL from windows(CR LF) to unix(LF), everything went well.
I did the conversion with Notepad++ very easily from: Edit -> EOL Conversion -> Unix(LF)
Unrelated to the OP's problem, but my issue was that I'm a noob shell scripter. All the other languages I've used require parentheses to invoke methods, whereas shell doesn't seem to like that.
function do_something() {
# do stuff here
}
# bad
do_something()
# works
do_something
In my case, I found that placing a here document (like sqplus ... << EOF) statements indented also raise the same error as shown below:
./dbuser_case.ksh: line 25: syntax error: unexpected end of file
So after removing the indentation for this, then it went fine.
Hope it helps...
Indentation when using a block can cause this error and is very hard to find.
if [ ! -d /var/lib/mysql/mysql ]; then
/usr/bin/mysql --protocol=socket --user root << EOSQL
SET ##SESSION.SQL_LOG_BIN=0;
CREATE USER 'root'#'%';
EOSQL
fi
=> Example above will cause an error because EOSQL is indented. Remove indentation as shown below. Posting this because it took me over an hour to figure out the error.
if [ ! -d /var/lib/mysql/mysql ]; then
/usr/bin/mysql --protocol=socket --user root << EOSQL
SET ##SESSION.SQL_LOG_BIN=0;
CREATE USER 'root'#'%';
EOSQL
fi
I have found that this is sometimes caused by running a MS Dos version of a file. If that's the case dos2ux should fix that.
dos2ux file1 > file2
I had this problem when running some script in cygwin. Fixed by running dos2unix on the script, with proper description of problem and solution given in that answer
You've got an unclosed quote, brace, bracket, if, loop, or something.
If you can't see it just by looking (I'd recommend a syntax colouring editor and a neat indentation style), take a copy of the script, and delete half of it, cutting it of somewhere that ought to be valid. If the script runs, as far as it can, then the problem is in the other half. Repeat until you've narrowed down the problem.
echo"==================PS COMMAND SNAPSHOT=============================================================="
needs to be
echo "==================PS COMMAND SNAPSHOT=============================================================="
Else, a program or command named echo"===... is searched.
more problems:
If you do a grep (-A1: + 1 line context)
grep -A1 "if " cldtest.sh
you find some embedded ifs, and 4 if/then blocks.
grep "fi " cldtest.sh
only reveals 3 matching fi statements. So you forgot one fi too.
I agree with camh, that correct indentation from the beginning helps to avoid such errors. Finding the desired way later means double work in such spaghetti code.
Helpful post, I found that my error was using else if instead of elif like so:
if [ -z "$VARIABLE1" ]; then
# do stuff
else if [ -z "$VARIABLE2" ]; then
# do other stuff
fi
Fixed it by changing to this:
if [ -z "$VARIABLE1" ]; then
# do stuff
elif [ -z "$VARIABLE2" ]; then
# do other stuff
fi
It can also be caused by piping out of a pair of curly braces on a line.
This fails:
{ /usr/local/bin/mycommand ; outputstatus=$? } >> /var/log/mycommand.log 2>&1h
do_something
#Get NOW that saved output status for the following $? invocation
sh -c "exit $outputstatus"
do_something_more
while this is allowed:
{
/usr/local/bin/mycommand
outputstatus=$?
} >> /var/log/mycommand.log 2>&1h
do_something
#Get NOW that saved output status for the following $? invocation
sh -c "exit $outputstatus"
do_something_more
I have encountered the same error while trying to execute a script file created in windows OS using textpad. so that one can select proper file format like unix/mac etc.. or recreate the script in linux iteself.

Resources