Remote Command executed via ssh does not return proper return code. Return error code is always "0", even condition failed

8,356

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
Share:
8,356
Sandeep Singh
Author by

Sandeep Singh

Updated on September 18, 2022

Comments

  • Sandeep Singh
    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
      Kusalananda over 5 years
      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).
    • Sandeep Singh
      Sandeep Singh over 5 years
      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'
    • terdon
      terdon over 5 years
      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.
    • Sandeep Singh
      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
      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
    Sandeep Singh over 5 years
    Thanks @kusalananda - For your valuable inputs. I will try these options and keep you update.
  • Kusalananda
    Kusalananda over 5 years
    Why echo the exit code at all? The exit code of ssh will be the exit code of the command.
  • Sandeep Singh
    Sandeep Singh over 5 years
    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.
  • jas-
    jas- over 5 years
    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’