1

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?

5
  • 2
    You are using double quoted strings within double quoted strings (see "$?" and the other things that you quote within the command you execute with ssh).
    – Kusalananda
    CommentedFeb 8, 2019 at 7:34
  • I 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'CommentedFeb 8, 2019 at 7:40
  • 2
    I 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 the grep line, and you have an extra " on the final fi line. Look at the syntax highlighting (colors) in your question. Please edit and fix it so you show the exact script you are running.
    – terdon
    CommentedFeb 8, 2019 at 10:34
  • @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.CommentedFeb 8, 2019 at 11:54
  • 1
    @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.
    – terdon
    CommentedFeb 8, 2019 at 12:01

3 Answers 3

4

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 
1
  • Thanks @kusalananda - For your valuable inputs. I will try these options and keep you update.CommentedFeb 8, 2019 at 7:45
0

Why not capture the result code from $? like so…

ssh user@host 'cmd arg;echo $?'

If you assign that to a variable you can then use a [ $n -gt 0 ] test against it.

2
  • Why echo the exit code at all? The exit code of ssh will be the exit code of the command.
    – Kusalananda
    CommentedFeb 8, 2019 at 13:11
  • I 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.CommentedFeb 8, 2019 at 18:22
0

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

2
  • I 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’
    – jas-
    CommentedFeb 10, 2019 at 13:19
  • Thanks Jas - For your Suggestion,I think you right. Array help in to close this in one connection only.CommentedFeb 11, 2019 at 8:29

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.