Exit code of previous command execution is always 0 -- In Remote Shell Execution $? - linux

I am trying to execute a script, In the midway of the script, it executes a part of the code in a remote shell and then again comes back to the same local shell.
However, my question is about the exit codes of the command executed in the remote shell. I am trying to do decision in remote with if-then-else based on the exit codes. When it didn't execute as expected I tried to narrow down the problem.
Here are my findings,
The output is always IP Found, as $? is always equal to 0.
ssh root#<remote server> bash -c "'
host www.google.com123
if [ $? != 0 ]
then
echo "Invalid Host"
else
echo "IP Found"
fi
'"
Also, in this case, the same output is expected
ssh root#<remote server> bash -c "'
host www.google.com
if [ $? != 0 ]
then
echo "Invalid Host"
else
echo "IP Found"
fi
'"
Ref: I got to know about this remote execution method from here
Please Help me understand this behavior of remote shell execution. Also, if there are any other ways to execute a part of a shell-script in remote through ssh please suggest.

The outermost quotes are double quotes, so $? is expanded locally before you ever run bash remotely. Instead, use
ssh root#<remote server> 'bash -c "
host www.google.com123
if [ \$? != 0 ]
then
echo \"Invalid Host\"
else
echo \"IP Found\"
fi
"'
Simpler is to avoid checking $? explicitly at all:
ssh root#<remote server> 'bash -c "
if ! host www.google.com123
then
echo \"Invalid Host\"
else
echo \"IP Found\"
fi
"'
Even simpler is not run a second unnecessary shell.
ssh root#<remote server> '
if ! host www.google.com123
then
echo "Invalid Host"
else
echo "IP Found"
fi
'

Related

Bash script that check connection with host:port using telnet and netcar

I have task to create quite complicated bash script, which at first part is checking the connection to host:port with telnet and- if telnet would fail or would not be installed, try the connection using netcat.
I have problem with loop, where it will skip netcat if telnet would connect to the host and also, if both- telnet and netcat would fail- script would finish with error message.
The script:
#!/bin/bash
echo Type host IP address
read REMOTEHOST
echo Type port number
read REMOTEPORT
TIMEOUT=5
echo quit | timeout --signal=9 5 telnet $REMOTEHOST $REMOTEPORT
if nc -w $TIMEOUT -z $REMOTEHOST $REMOTEPORT; then
echo "I was able to connect to ${REMOTEHOST}:${REMOTEPORT}"
else
echo "Connection to ${REMOTEHOST}:${REMOTEPORT} failed. Exit code from Netcat was ($?)."
fi
You can use the $? variable to get the exit code from the last command.
I found that your original telnet command exits with error code 1 on my system because the escape character is ^]. When I telnet manually I need to hit ctrl-] to enter the telnet prompt, then I can enter 'quit'.
The trick here is you cannot just type ^], you have to type ctrl-v ctrl-]
ctrl-v tells the system to capture the next ctrl character.
The following gives me an exit code of 0, and you can verify by running it manually with echo $? at the command line
-- remember to use ctrl-v ctr-]
$ (echo ^]; echo quit) | timeout --signal=9 5 telnet <REMOTEHOST> <REMOTEPORT>
$ echo $?
Then you can use this in your script:
#!/bin/bash
echo Type host IP address
read REMOTEHOST
echo Type port number
read REMOTEPORT
TIMEOUT=5
(echo ^]; echo quit) | timeout --signal=9 5 telnet $REMOTEHOST $REMOTEPORT > /dev/null 2>&1
TELNET_EXIT_CODE=$?
if [[ $TELNET_EXIT_CODE -ne 0 ]]; then
nc -w $TIMEOUT -z $REMOTEHOST $REMOTEPORT > /dev/null 2>&1
NC_EXIT_CODE=$?
fi
if [[ $TELNET_EXIT_CODE -eq 0 ]] || [[ $NC_EXIT_CODE -eq 0 ]]; then
echo "success"
else
echo "fail"
fi
Tested on Ubuntu 20.04.04, GNU bash version 5.0.17, Telnet version 0.17-41

how to check if bash function exist on remote computer

I read various answers on similar topic, but I still can't deal with my problem. Namely, on the remote computer I have a .bashrc file with a bunch of custom made functions. I would like to check if that function exists in that file. Just to add that the script constantly reports that there is a specified function on the remote computer even though it is not. This is what I have done so far:
echo "Enter IP addres of the remote PC [def host#XX.XX.XX.XX]"
read ip
ip=${ip:-host#XX.XX.XX.XX}
$(ssh $ip "[ '$(type -t $1)' = function ]")
if [ $? -eq 0 ]; then
echo "function exist"
else
echo 'function doesnt exist'
fi
$(...)is expanded localy inside " quotes. Reseach difference between single and double quotes.
the_function_you_want_to_check=something
ssh "$ip" '[ "$(type -t "'$the_function_you_want_to_check'")" = function ]'
Do not use $?. Just:
if ssh stuff...; then
echo yes
else
echo no
fi
Thank you for your prompt response. Please note that $1 is actually the first parameter of the bash functions that I run on my local computer. Now, the change you suggested reports that there is no function on the remote computer even though it exists. More complete function that I run on the local machine is:
appendFunction_to_remotePC(){
echo "Enter the IP addres of the PC [def host#XX.XX.XX.XX]"
read ip
ip=${ip:-host#XX.XX.XX.XX}
if ssh "$ip" '[ "$(type -t "'$1'")" = function ]'; then
echo yes
else
echo no
fi
}
I call the function on the local computer in the usual way:
$ appendFunction_to_remotePC "test"

Getting exit code from SSH command running in background in Linux (Ksh script)

I trying to run few commands to be executed in parallel in couple of remote servers using SSH and i need to get the correct exit code from those commands but with no success.
I am using the command below
(ssh -o LogLevel=Error "remote_server1" -n " . ~/.profile 1>&- 2>&-;echo "success" 2>&1 > /dev/null" ) & echo $? > /tmp/test1.txt
(ssh -o LogLevel=Error "remote_server2" -n " . ~/.profile 1>&- 2>&-;caname 2>&1 > /dev/null" ) & echo $? > /tmp/test2.txt
The result is always "0" (echo $?) even i forced to failed like the second example above. Any idea?

SSH Remote command exit code

I know there are lots of discussions about it but i need you help with ssh remote command exit codes. I have that code:
(scan is a script which scans for viruses in the given file)
for i in $FILES
do
RET_CODE=$(ssh $SSH_OPT $HOST "scan $i; echo $?")
if [ $? -eq 0 ]; then
SOME_CODE
The scan works and it returns either 0 or (1 for errors) or 2 if a virus is found. But somehow my return code is always 0. Even, if i scan a virus.
Here is set -x output:
++ ssh -i /home/USER/.ssh/id host 'scan Downloads/eicar.com; echo 0'
+ RET_CODE='File Downloads/eicar.com: VIRUS: Virus found.
code of the Eicar-Test-Signature virus
0'
Here is the Output if i run those commands on the "remote" machine without ssh:
[user#ws ~]$ scan eicar.com; echo $?
File eicar.com: VIRUS: Virus found.
code of the Eicar-Test-Signature virus
2
I just want to have the return Code, i dont need all the other output of scan.
!UPDATE!
It seems like, echo is the problem.
The reason your ssh is always returning 0 is because the final echo command is always succeeding! If you want to get the return code from scan, either remove the echo or assign it to a variable and use exit. On my system:
$ ssh host 'false'
$ echo $?
1
$ ssh host 'false; echo $?'
1
$ echo $?
0
$ ssh host 'false; ret=$?; echo $ret; exit $ret'
1
$ echo $?
1
ssh returns the exit status of the entire pipeline that it runs - in this case, that's the exit status of echo $?.
What you want to do is simply use the ssh result directly (since you say that you don't want any of the output):
for i in $FILES
do
if ssh $SSH_OPT $HOST "scan $i >/dev/lull 2>&1"
then
SOME_CODE
If you really feel you must print the return code, that you can do that without affecting the overall result by using an EXIT trap:
for i in $FILES
do
if ssh $SSH_OPT $HOST "trap 'echo \$?' EXIT; scan $i >/dev/lull 2>&1"
then
SOME_CODE
Demo:
$ ssh $host "trap 'echo \$?' EXIT; true"; echo $?
0
0
$ ssh $host "trap 'echo \$?' EXIT; false"; echo $?
1
1
BTW, I recommend you avoid uppercase variable names in your scripts - those are normally used for environment variables that change the behaviour of programs.

script to read a file with IP addresses and login

I have a file named "host.txt" with listing IP addresses of two systems.
~] cat hosts.txt
10.1.1.10
10.1.1.20
Using below script I am trying to login to each system, check status of a service and print the output of each system. The script prompts to login, however does not continue to execute the /opt/agent.sh status command. Can someone please help fix this script?
#!/bin/bash
for HOST in `cat hosts.txt`
do
ssh root#$HOST
STATUS=`/opt/agent.sh status | awk 'NR==1{print $3 $4}'`
echo $STATUS
if [ $STATUS! == "isrunning" ]; then
echo "$host == FAIL"
else
echo "$host == PASS"
fi
You script does not continue until the ssh command completes, which does not happen the interactive shell on $HOST that you started with ssh exits. Instead, you want to execute a script on $HOST.
(Also, note the correct way to iterate over the contents of hosts.txt.)
#!/bin/bash
while read HOST; do
do
if ssh root#$HOST '
STATUS=`/opt/agent.sh status | awk 'NR==1{print $3 $4}'`
[ "$STATUS" = "isrunning" ]
'; then
echo "$HOST == FAIL"
else
echo "$HOST == PASS"
fi
done < hosts.txt
The remote script simply exits with the result of comparing $STATUS to "isrunning". An if statement on the local host outputs a string based on the that result (which is the result of the ssh command itself). This saves the trouble of having to pass the value of $HOST to the remote host, simplifying the quoting required for the remote script.

Resources