how to check if bash function exist on remote computer - linux

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"

Related

How do I properly use SSH heredoc?

This question is somewhat related to the question I asked here, but it has not been adequately answered. What interests me here is the following:
When I run the command type -t test on a remote computer, I get the answer 'function' because the 'test' is an existing function inside the .bashrc file on the remote computer.
However, when I run this SSH command on the local computer,
s="$(
ssh -T $HOST <<'EOSSH'
VAR=$(type -f test)
echo $VAR
EOSSH
)"
echo $s
I don't get anything printed. The first question would be how do I make this work?
The second question builds on the previous one. That is, my ultimate goal is to define on a local computer which function I want to check on a remote computer and come up with an adequate answer, ie.:
a="test"
s="$(
ssh -T $HOST <<'EOSSH'
VAR=$(type -f $a)
echo $VAR
EOSSH
)"
echo $s
So, I would like the variable s to be equal to 'function'. How to do it?
how do I make this work?
Either load .bashrc (. .bashrc) or start an interactive session (bash -i).
Because your work is not-interactive, if you want .bashrc loaded and it has no protection against non-interactive use, just load it. If not, maybe move your function somewhere else, to something you can source. If not, be prepared that interactive session may print /etc/motd and /etc/issue and other interactive stuff.
Remove -T - you do not need a tty for non-interactive work.
I would like the variable s to be equal to 'function'. How to do it?
I recommend using declare to transfer all the work and context that you need, which is flexible and works generically, preserves STDIN and doesn't require you to deal with the intricacies escaping inside a here document. Specifically request bash shell from the remote and use printf "%q" to properly escape all the data.
functions_to_check=(a b c)
fn_exists() { [[ "$(LC_ALL=C type -t -- "$1" 2>/dev/null)" = function ]]; }
work() {
for f in "${functions_to_check[#]}"; do
if fn_exists "$f"; then
echo "Great - function $f exists!"
else
echo "Och nuu - no function $f!"
fi
done
}
ssh "$host" "$(printf "%q " bash -c "
$(declare -p function_to_check) # transfer variables
$(declare -f fn_exists work) # transfer functions
work # run the work to do
")"

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

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
'

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.

grep statement in bash

I am using a for loop to connect to a list of servers and perform some simple commands. If the server is not accessible then stderr is written to a file. I then grep that file for the server name. It seems relatively simple and for some reason it isn't working. For troubleshooting purposes I have narrowed my server list to two servers and only run simple commands.
for i in $(cat serverlist)
do
nexec -i $i hostname 2>>errorlog.txt
if grep -q $i errorlog.txt; then echo "error accessing" $i
else echo "was able to connect to" $i
fi
done
So in the serverlist I have defined two incorrect hosts for troubleshooting purposes. Nexec tries to connect to each and perform the hostname command. If it is unable to connect an error message is printed to errorlog.txt
e.g.,
nexec: Error accessing host test1
Since both servers are incorrectly specified I am not able to connect to either. Again for troubleshooting purposes.
When grep runs the first time against $i which is the first server in the list it doen't find any matches in error.txt. However, it should. If I cat the results instead of grepping it is there.
I am actually doing this in bladelogic so the rules are a bit different. It should still work.
while read -r i <&3; do
nexec -i "$i" hostname 2>>"errorlog.$i.txt" || {
echo "nexec for $i exited with status $?" >&2
continue
}
# check for case where it claimed success but actually failed
# if nexec is written correctly, you don't need any of this logic
# ...and can completely remove the rest of the loop.
if grep -q -e "$i" "errorlog.$i.txt"; then
echo "error accessing $i" >&2
else
echo "was able to connect to $i" >&2
fi
done 3<serverlist
# and combine all the individual logs into one file:
cat errorlog.*.txt >errorlog.txt && rm -f -- errorlog.*.txt
Not familiar with nexec, but I imagine something like this is what you are looking for
for i in $(cat serverlist)
do
if [ ! "$(nexec -i $i hostname)" ]
then echo "error accessing" $i
else echo "was able to connect to" $i
fi
done

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