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?

  • 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 Feb 8 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 sandeepj@10.25.59.2 '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' – Sandeep Singh Feb 8 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 Feb 8 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. – Sandeep Singh Feb 8 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 Feb 8 at 12:01
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
  • Thanks @kusalananda - For your valuable inputs. I will try these options and keep you update. – Sandeep Singh Feb 8 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.

  • Why echo the exit code at all? The exit code of ssh will be the exit code of the command. – Kusalananda Feb 8 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. – Sandeep Singh Feb 8 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

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.