0

This script provides the expected output, but throw the error "bash: line 1: [: -ne: unary operator expected". Techies help to fix this.

#!/bin/bash
USR="root"

# Email
SUBJECT="NTP Service Status Report"
EMAIL="[email protected]"
EMAILMESSAGE="/tmp/ntp_status.txt"

# create new file
>$EMAILMESSAGE

# connect each host and pull up user listing
for host in `cat SAP_Prod_servers_51`
do
echo "--------------------------------" >>$EMAILMESSAGE
echo "* HOST: $host " >>$EMAILMESSAGE
echo "--------------------------------" >>$EMAILMESSAGE
ssh $USR@$host "UP=$(ps -ef | grep -v grep | grep ntpd | wc -l);
if [ "$UP" -ne 1 ];
then
        echo "NTP is down.";
        sudo service ntpd start

else
        echo "NTP Service is running.";
fi" >> $EMAILMESSAGE
done

# send an email using /bin/mail
/bin/mail -s "$SUBJECT" "$EMAIL" < $EMAILMESSAGE
5
  • 1
    You're missing a " on the ssh line: ssh $USR@$host "UP=$(ps -ef | grep -v grep | grep ntpd | wc -l)"; Commented Dec 20, 2019 at 3:41
  • ... and after the edit, you can see the missing quote in the coloring of the code.
    – NickD
    Commented Dec 20, 2019 at 3:50
  • 1
    @ajgringo619 the "missing" " appears to be after the fi a few lines down - presumably because the intention is to run the whole thing on the remote host (it wouldn't make sense to assign UP on the remote host then try to test it on the local host). Perhaps the outer " just need to be changed to '? Commented Dec 20, 2019 at 3:51
  • @steeldriver - that's very likely. Commented Dec 20, 2019 at 3:55
  • I tend to monitor service statuses with a Nagios plug-in.
    – JdeBP
    Commented Dec 20, 2019 at 10:00

1 Answer 1

2

The base problem is that the command being sent over ssh is in double-quotes, so the $( ... ) and $UP are being expanded by the local shell before the command is passed to the ssh command and thence to the remote shell.

Also, quotes don't nest, so the double-quotes in the command string don't do what you want -- the first of each pair is treated as a close-quote (matching whichever was before it), the section that's supposed to be quoted is then not in quotes at all, and the next double-quote starts a new quoted section. Since those are quotes around sections of the argument, the local shell removes them from the argument before passing it to ssh.

Between those two things, and assuming that ntpd is not running on the local computer, here's what actually gets passed to the remote computer as a command:

UP=       0;
if [  -ne 1 ];
then
        echo NTP is down.;
        sudo service ntpd start

else
        echo NTP Service is running.;
fi

The [ -ne ] expression is missing its left operand (remember, the quotes got removed), so [ complains about that. I'm not sure why it thinks that's on line 1, as it looks like line 2 to me.

Solution 1: Use single-quotes around the whole command. Since it doesn't have any single-quotes in it nesting isn't an issue, and single-quotes suppress expansion of everything, so the various $ expansions happen on the remote system.

Solution 2: Pass the commands as a (quoted) here-document instead of an argument (BTW, I also double-quoted $EMAILMESSAGE on general principles, and removed semicolons from the ends of lines where they're not needed):

ssh $USR@$host >> "$EMAILMESSAGE" <<'EOF'
UP=$(ps -ef | grep -v grep | grep ntpd | wc -l);
if [ "$UP" -ne 1 ]
then
        echo "NTP is down."
        sudo service ntpd start

else
        echo "NTP Service is running."
fi
EOF

Solution 3: Skip the variable, and just use grep -q directly as the if test, and either escape the internal double-quotes or switch to single-quotes:

ssh $USR@$host "if ps -ef | grep -v grep | grep -q ntpd
then
        echo \"NTP is down.\"
        sudo service ntpd start

else
        echo \"NTP Service is running.\"
fi" >> "$EMAILMESSAGE"
6
  • 1
    Note that script expects the ssh command to set UP locally. Setting the UP variable on the remote system won't do any good. The simple fix is to change ssh ... "UP=$(...)" into UP=$( ssh ... ).
    – Kusalananda
    Commented Dec 20, 2019 at 7:21
  • One could even do if ! ssh remote pgrep ntpd 2>/dev/null; then echo not running; fi.
    – Kusalananda
    Commented Dec 20, 2019 at 7:31
  • @Kusalananda After seeing your comment, I thought that might be possible... but it won't work; service ntpd start has to be run on the remote system, therefore all the testing and branching has to happen there as well. Commented Dec 20, 2019 at 7:31
  • Doesn't the service command have a check or test or whatever sub-command that tells you whether a service is running? if ! ssh remote service check ntpd; then echo not running; fi
    – Kusalananda
    Commented Dec 20, 2019 at 7:32
  • I see what you mean now, yes, the service restart has to run on the remote host. I think the testing done in the script is far too involved. Personally I would just have used ssh remote 'pgrep ntpd || service start ntpd' or something similar.
    – Kusalananda
    Commented Dec 20, 2019 at 7:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .