storing output of a command that fails to execute - bash

I am trying store the output of command to a variable in a script and print the result depending on output stored in variable..
For example, in this script, I am trying print the status of an agent installed on few systems read from lab.txt file. If the status matches with "isrunning", it prints that "agent is installed".
~]# cat lab.txt
192.168.1.1
192.168.1.2
Here is the script -
#!/bin/bash
while read host; do
status=$(ssh -n root#$host /opt/agent/bin/agent.sh status | awk 'NR==1{print $3 $4}')
if [ $status != isrunning ]
then
echo "agent is not installed"
else
echo "agent is installed"
fi
done < lab.txt
The issue here is, if the command returns an error as becuase the /opt/agent directory was not present on system 192.168.1.2, the "agent is not installed" message is not printed. What could be wrong here?
~]# ./script.sh
root#192.168.1.1:
agent is installed
root#192.168.1.2:
bash: /opt/agent/bin/agent.sh: No such file or directory
./script.sh: line 5: [: !=: unary operator expected
agent is installed

$status is not initialized, so the condition [ status != isrunning ] is not satisfied. Something like:
if [ "$status" != isrunning ]
should solve this and get rid of your error of unary operator expected too.

Related

Testing grep output in bash

I'm looking for a way to act differently in my bash script depending on my external IP address. To be more specific if my external IP address is 111.111.111.111 then do some action, otherwise do something else.
This is my code:
extIP=$(curl ifconfig.me | grep 111.111.111.111)
if [ -? ${extIP} ]
then
runExecutable
else
echo "111.111.111.111 is not your IP."
fi
I don't know how to test extIP.
Try this
echo 'Enter the IP Address you want to test'
read IP_ADDRESS
extIP=$(curl ifconfig.me | grep -o '[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*')
if [ "$IP_ADDRESS" == "$extIP" ]
then
bash runExecutable.sh
exit 0
fi
echo '${IP_ADDRESS} is not your IP'
exit 1 # if it's bad or just exit 0 otherwise
Just run the curl/grep command the check the exit status
curl ifconfig.me | grep -s 111.111.111.111
if [ "$?" == "0" ]
then
runExecutable
else
echo "111.111.111.111 is not your IP."
fi
You should test the exit code of your command pipeline directly with if, like this:
addr="111.111.111.111"
if curl -s ifconfig.me | grep -qF "$addr"; then
runExecutable "$addr" ...
else
echo "$addr is not your IP."
fi
Also, you probably want to silence the curl's progress output with -s and grep's matches with -q, use a fixed string search in grep with -F, and store your IP address in a variable for easier later reuse.
Note the [ is actually a shell command that exits with 0 if condition that follows is true, or with 1 otherwise. if than uses that exit code for branching.
See this bash pitfall for more details.

How to get error number in $? and the o/p in response

I am trying to connect to a host and run the netstat command,using the below:
NET_STAT=$(ssh $hostname netstat -an 2>&1)
if [ $? -ne 0 ]; then
echo “error occurred”
When SSH is successful i should have netstat o/p in NET_STAT.
When SSH fails I should have Error written into NET_STAT.(because i added 2>&1)
So to check if the command succeeded I use “$?”.
But the problem is whether the command fails or succeeds $? is always 0. I think this is because the second part of the command(2>&1) always succeeds and so I get 0.
Is there a way that I get the return code as non-zero so that I can distinguish success and failure. And also get the proper o/p in NET_STAT.
Here is an example:
hostname=1.2.3.4
NET_STAT=$(ssh $hostname netstat -an 2>&1)
echo "val of err is $NET_STAT"
echo "val of ret val is $?"
output
=========
val of err is ssh: 1.2.3.4: node name or
service name not known
val of ret val is 0
Why not just check $NET_STAT for something that confirms that the netstat command has worked:
if echo $NET_STAT | grep "^Active" > /dev/null
then
echo "All ok"
else
echo "not ok"
fi

Error in two scripts: "unary operator expected" and "integer expression expected"

I wrote two scripts which try to do the same action in two different ways, but I get errors each time I run those. Kindly requesting your help to correct my scripts and to improve my knowledge as well. All I am trying to do the vps setup in a single script. Following two scripts are just a portion of it which get errors each time.
1) Script to set hostname through cpanel xml-api for a vps in openvz node
cat vpstest.sh
#/bin/bash
hostname_status=`curl -sku root:PASSWORDHERE "https://ip.x.x.x:2087/xml-api/sethostname?hostname=server.domain.com" | awk -F"[<>]" '/status/{print $3}' | head -n1`
if [ $hostname_status -eq 1 ]; then
echo "Hostname set"
else
echo "Failed setting hostname"
fi
Output:
# ./vpstest.sh
./vpstest.sh: line 3: [: -eq: unary operator expected
Failed setting hostname
2) Script to set hostname via command line in an openvz node
cat vpstest1.sh
#!/bin/bash
hostname_status=`vzctl set containerID --hostname server.domain.com --save`
if [ "$hostname_status" -eq 1 ] ; then
echo "Hostname set"
else
echo "Failed setting hostname"
fi
Output:
# ./vpstest1.sh
./vpstest1.sh: line 3: [: CT configuration saved to /etc/vz/conf/containerID.conf: integer expression expected
Failed setting hostname
Can someone help to clear these errors?
First, the output of vzctl set containerID --hostname server.domain.com --save seems not be an integer value whereas -eq is only provided to do comparisons between integers values.
This would explain the following error :
integer expression expected
Then, you should read this reminder about the necessity (or not) to protect your variables with double quotes.
This would explain the following error, you could use something like :
./vpstest.sh: line 3: [: -eq: unary operator expected
If you want to check the status of a command :
command >/dev/null 2>&1 && echo "success" || echo "fail"
# or
if command >/dev/null 2>&1; then
echo "success"
else
echo "fail"
fi
You could also check the variable $? which correspond to the status of the previous command (0 when that command success or another integer value which is 1 in most of cases, or more).

read a list of IP address and execute commands depending on OS type

I am working on a script to read from a file having multiple IP addresses, login to each system (no ssh keys involved and manually entering password), execute a command depending on OS type and print the result.
Here is how IPs are defined in the hosts.txt file
#~] cat hosts.txt
10.6.3.131
10.6.3.132
10.6.3.11
10.6.3.12
When I execute the below script, the following errors are shown. Also, The script does not prompt for 2nd and rest IPs in the list. What could be causing this?
# ./hq-test1.sh
root#10.6.3.131's password:
awk: cmd. line:1: NR==1{print
awk: cmd. line:1: ^ unexpected newline or end of string
bash: line 2: [: !=: unary operator expected
10.6.3.131 == PASS
This is the script used in test :
#!/bin/bash
while read HOST; do
if ssh root#$HOST '
STATUS=`awk 'NR==1{print $1}' /etc/*release`
[ $STATUS != "CentOS" ]
'; then
echo "$HOST == FAIL"
else
echo "$HOST == PASS"
fi
done < hosts.txt
Your script isn't closing stdin while running the ssh command so only the first host of the list is processed.
I also simplified the test, as awk is able to check the OS name and the temporary variable is unnecessary.
while read host; do
if ssh -n root#$host '[ "$(awk "/CentOS/{print}" /etc/*release)" ] '
then
echo "$host == PASS"
else
echo "$host == FAIL"
fi
done < hosts.txt
This worked for me. As I already wrote, it's just a quoting issue.
#!/bin/bash
echo localhost | while read HOST; do
if ssh root#$HOST '
STATUS=`awk "NR==1{print \$1}" /etc/*release`
[ $STATUS != "CentOS" ]
'; then
echo "$HOST == FAIL"
else
echo "$HOST == PASS"
fi
done

shell script to check if program should be running and restart it if appropriate

I have the following script
#!/bin/sh
if [cat stream_should_be_running.txt == 'true']; then #file will either contain true or false
if [ps ax|grep -v grep|grep tracker_stream]; then # check if stream is currently running
exit 0
else
/usr/local/bin/python2.7 ~/webapps/dashboard/fbadmin/manage.py tracker_stream; # restart stream
exit 0
else
exit 0
fi
This script should check if a daemon script is suppose to be running. If it is suppose to be running then it checks to see if the script is running and restarts it if it isn't. Currently I get syntax error: unexpected end of file when I try to running the file manually.
So two questions:
why am i pulling the syntax error
outside of this should this script run properly?
Thanks
EDIT:
here is an updated version of the script and a few notes:
#!/bin/sh
set -vx; # turn on shell debugging
if [[ "$(cat stream_should_be_running.txt)" == "true" ]]; then
if [ ps ax|grep -v grep|grep -q tracker_stream ]; then
exit 0
else
/usr/local/bin/python2.7 ~/webapps/dashboard/fbadmin/manage.py tracker_stream;
exit 0
fi
else
exit 0
fi
to note:
vim marks $(...) as a syntax error ( i don't know if that matters)
ps ax|grep -v grep|grep -q tracker_stream , ps ax|grep -v grep|grep tracker_stream , and cat stream_should_be_running.txt all execute properly from the command line
EDIT 2:
shell debugging gives the error
$ sh stream_checker.sh
+ $'\r'
: command not foundline 3:
if [[ "$(cat stream_should_be_running.txt)" == "true" ]]; then
echo 'test';
if [ ps ax|grep -v grep|grep -q tracker_stream ]; then
exit 0
else
/usr/local/bin/python2.7 ~/webapps/dashboard/fbadmin/manage.py tracker_stream;
exit 0
fi
else
exit 0
fi
stream_checker.sh: line 15: syntax error: unexpected end of file
so the only things that come before where the + $'\r' is returns are #!/bin/sh and set -vx.
This is running on a linux system. The my local machine is osx lion and the live machine is a linux server on webfaction.
1) I think I got it...
I used the '-s' switch in pidof to only get one result.
The '-z' switch means "return true if the string is empty".
#!/bin/sh
PID=$(pidof -s tracker_stream);
if [ $(cat stream_should_be_running.txt) = "true"]; then #file will either contain true or false
if [ -z $PID ]; then # check if stream is currently NOT running
/usr/local/bin/python2.7 ~/webapps/dashboard/fbadmin/manage.py tracker_stream; # restart stream
exit 0;
fi
fi
EDIT: From the last note you posted it looks like you might have a Ctrl-M char (^M), somewhere on your file.
It's not merely a ^ followed by a M, it's a end of line character.
You could open your file with vim -b to check if you see any of those characters.
Then type:
:%s/^V^M//g
That command reads like "match all (^M) chars and substitute them with void".
In short it will remove all (^M) chars from your file.
The (^V^M) bit means that you have to hit CTRL-V CTRL-M, in order to insert the (^M) char.
2) what exactly do you mean by "outside of this"?
your square brackets need spaces around them, i.e.
if [ ps ax|grep -v grep|grep tracker_stream ] ;
AND more importantly, you need to use command substitution so your script can get the value inside stream_should_be_running.txt using $( cat ... ), i.e.
if [[ "$(cat stream_should_be_running.txt)" == 'true' ]] ; then
#file will either contain true or false
if[ ps ax|grep -v grep|grep -q tracker_stream ] ; then
# check if stream is currently running
exit 0
else
/usr/local/bin/python2.7 ~/webapps/dashboard/fbadmin/manage.py tracker_stream;
# restart stream
exit 0
else
exit 0
fi
Also better to dbl-quote the value returned by $(cat ...) in case some how there are spaces in the file.
Finally, turn on shell debugging by adding set -vx near top script. Then you can each line/block of code as it being executed, AND the values that are substituted for variables.
I hope this helps.

Resources