Remote Command executed via ssh does not return proper return code. Return error code is always "0", even condition failed
Solution 1
After applied suggested changes if find two ways to achieve my result.
First Solution : Using for Loop
#!/bin/bash/expect
DATE=`date "+%d-%m-%Y_%H-%M-%S"`
for i in `cat /root/project_finduser/serverlist`;
do
echo -e "\n*******************"
echo -e "$i"
for a in `cat /root/project_finduser/userslist`;
do
echo -e "\n"
echo -n "$a :"
if ssh "root@${i}" cat /etc/passwd | grep -w -q -F -e "$a";
then
echo "User exsits"
else
echo "User not exsits"
fi
done
done >>"/tmp/userfind_${DATE}.txt"
Second Solution : Using While loop { I have passed -n option with ssh command becuase while loop stop reading argument from file after first line}
#!/bin/bash
DATE=`date "+%d-%m-%Y_%H-%M-%S"`
while IFS= read -r ipaddress;
do
echo -e "\n*******************"
echo -e "$ipaddress"
while IFS= read -r userid;
do
echo -e "\n"
echo -n "$userid : "
if ssh -n "root@${ipaddress}" getent passwd "$userid" >/dev/null;
then
echo -n "User exsits"
else
echo -n "User not exsits"
fi
done < /root/project_finduser/userslist
done < /root/project_finduser/serverlist >"/tmp/userfind_${DATE}.txt"
Output :
192.168.56.103
sandeep : User exsits
student : User exsits
ram : User not exsits
sita : User not exsits
swati : User exsits
student : User exsits
192.168.56.104
sandeep : User not exsits
student : User exsits
ram : User not exsits
sita : User not exsits
swati : User not exsits
student : User exsits
Solution 2
The main issue in your code is that $?
is expanded before ssh
is called. This is due to quoting. All expansions in a double-quoted string are expanded before the string is used. In addition to that, the double-quoted string that you are using with ssh
contains other double-quoted sections. These sections would be unquoted, just like the substring abc
is unquoted in "123"abc"456"
.
Instead of trying to execute a complicated command on the remote host, just let the ssh
command cat
the passwd
file, then grep
that:
if ssh -n "sandeep@$ipaddress" cat /etc/passwd | grep -q -F -e "$userid"
then
echo "User exists"
else
echo "User does not exist"
fi >>"/tmp/userfind_$DATE.txt"
Also, consider reading from the user and server list using a while loop instead:
while IFS= read -r userid; do
# ...
done </home/sandeep/Project_finduser01/userslist
You may also redirect the outermost loop to your output file instead of redirecting every single echo
:
while ...; do
while ...; do
# stuff
done <userlist
done <serverlist >"/tmp/userfind_$DATE.txt"
If your user list is long, you may want to only get the passwd
from the remote host once, and then query that several times
while ...; do
scp "sandeep@$ipaddress:/etc/passwd" passwd.tmp
while ...; do
if grep -q -F -e "$userid" passwd.tmp; then
# exists
fi
done <userlist
done <serverlist >"/tmp/userfind_$DATE.txt"
Even more efficiently would be to read the user list into an awk
array and then match the usernames from the passwd
file against them. That would get rid of the innermost loop entirely.
The username is found in a particular field in the passwd
file. With your approach, you would match both marc
and marco
if you searched for marc
. To match a bit more carefully, consider using a pattern such as "^$userid:"
instead of matching against the whole line (and drop the -F
that I introduced above if you're still using grep
to do this).
You may also avoid the parsing of the passwd
file completely with
getent passwd "$userid" >/dev/null
This returns a zero exit code (success) if the user exists and non-zero otherwise.
I.e.,
if ssh -n "sandeep@$ipaddress" getent passwd "$userid" >/dev/null
then
# exists
else
# does not exist
fi
This would do one ssh
call against the remote host per user though. This could be made a bit more efficient by not closing the connection between each call (the below would keep the connection open for one minute):
if ssh -n -o ControlMaster=auto -o ControlPersist=1m "sandeep@$ipaddress" getent passwd "$userid" >/dev/null
then
# exists
else
# does not exist
fi
Sandeep Singh
Updated on September 18, 2022Comments
-
Sandeep Singh almost 2 years
I am not getting proper exit return code during execution of remote script on a Linux machine. This script is intended for checking whether a user exists or not.
My Script is below :-
#!/bin/bash DATE=`date "+%d-%m-%Y_%H:%M:%S"` for i in `cat /home/sandeep/server_ip_list/serverlist_New` do ipaddress=${i} echo -e "\n***************" >> /tmp/userfind_${DATE}.txt echo -e "$ipaddress" >> /tmp/userfind_${DATE}.txt for b in `cat /home/sandeep/Project_finduser01/userslist` do userid=${b} echo -e "\n" >> /tmp/userfind_${DATE}.txt echo -n "$userid" >> /tmp/userfind_${DATE}.txt ssh -t sandeep@${ipaddress} "grep $userid /etc/passwd > /dev/null; if [ "$?" = "0" ]; then echo -n " : User exsits" else echo -n " : User not exsits" fi" >> /tmp/userfind_${DATE}.txt done done
I am always getting the output below, whether the user exists or not:
*************** 10.25.59.12 sandeepj: User exsits pravin: User exsits ram: User exsits sita: User exsits raj.singh: User exsits
How to manipulate remote exit status codes at server side?
-
Kusalananda over 5 yearsYou are using double quoted strings within double quoted strings (see
"$?"
and the other things that you quote within the command you execute withssh
). -
Sandeep Singh over 5 yearsI removed "" from $? but still same output. + for b in '
cat /home/sandeepj/Project_finduser01/userslist
' + userid=raj.singh + echo -e '\n' + echo -n raj.singh + ssh -t [email protected] 'grep raj.singh /etc/passwd > /dev/null; if [ 0 = 0 ]; then echo -n ' : User 'exsits > /tmp/status else echo -n ' : User not 'exsits > /tmp/status fi' -
terdon over 5 yearsI this really your script? If you run what you show, you will get syntax errors because of the wrong quotes. You need a closing
"
on thegrep
line, and you have an extra"
on the finalfi
line. Look at the syntax highlighting (colors) in your question. Please edit and fix it so you show the exact script you are running. -
Sandeep Singh over 5 years@terdon - Script is working fine and i am using same " " to pass my multiple command with ssh.it will be very help full if you guide me any idea or alternate about this code. I am beginner in Shell Scripting track.
-
terdon over 5 years@SandeepSingh if the script is working, then you are not running the script you have in your question. Please correct the issues I mentioned in my comment.
-
-
Sandeep Singh over 5 yearsThanks @kusalananda - For your valuable inputs. I will try these options and keep you update.
-
Kusalananda over 5 yearsWhy echo the exit code at all? The exit code of
ssh
will be the exit code of the command. -
Sandeep Singh over 5 yearsI tried this ssh user@host ' cmd $arg; if [ $? -eq 0 ] but its doesn't work in, condition of local argument passed to remote ssh command. $? Value in if condition always come null.
-
jas- over 5 yearsI am not sure as an admin or security auditor I would like to see a connection hammering situation like this. Why not use an array to hold all of them in one connection?
users=( $(ssh user@host ‘getent passwd’) )
then pluck out those you expect to exist?echo ${users[@]} | tr ‘ ‘ ‘\n’ | egrep ‘user1|user2’