Skip to content
Advertisement

Shell Script ssh $SERVER >> EOF

I have a handy script here that can return accounts that will expire in 7 Days or have expired. I wanted to allow this to run on multiple hosts with out putting the script on each individual host, I added the for loop and the ssh $SERVER >> EOF part but it will just run the commands off they system that is running the script.

I believe the error is with ssh $SERVER >> EOF but I am unsure as the syntax looks correct.

#!/bin/bash

for SERVER in `cat /lists/testlist`
do
  echo $SERVER

  ssh $SERVER >> EOF
    sudo cat /etc/shadow | cut -d: -f1,8 | sed /:$/d > /tmp/expirelist.txt
    totalaccounts=`sudo cat /tmp/expirelist.txt | wc -l`
    for((i=1; i<=$totalaccounts; i++ ))
    do
      tuserval=`sudo head -n $i /tmp/expirelist.txt | tail -n 1`
      username=`sudo echo $tuserval | cut -f1 -d:`
      userexp=`sudo echo $tuserval | cut -f2 -d:`
      userexpireinseconds=$(( $userexp * 86400 ))
      todaystime=`date +"%s"`
      if [[ $userexpireinseconds -ge $todaystime ]] ;
      then
        timeto7days=$(( $todaystime + 604800 ))
        if [[ $userexpireinseconds -le $timeto7days ]];
        then
          echo $username "is going to expire in 7 Days"
        fi
      else
        echo $username "account has expired"
      fi
    done
    sudo rm /tmp/expirelist.txt
  EOF
done

Advertisement

Answer

Here documents are started by << EOF (or, better, << 'EOF' to prevent the body of the here document being expanded by the (local) shell) and the end marker must be in column 1.

What you’re doing is running ssh and appending standard output to a file EOF (>> is an output redirection; << is an input redirection). It is then (locally) running sudo, etc. It probably fails to execute the local file EOF (not executable, one hopes), and likely doesn’t find any other command for that either.

I think what you’re after is this (where I’ve now replaced the back-ticks in the script with $(...) notation, and marginally optimized the server list generation for use with Bash):

#!/bin/bash

for SERVER in $(</lists/testlist)
do
  echo $SERVER

  ssh $SERVER << 'EOF'
    sudo cat /etc/shadow | cut -d: -f1,8 | sed '/:$/d' > /tmp/expirelist.txt
    totalaccounts=$(sudo cat /tmp/expirelist.txt | wc -l)
    for ((i=1; i<=$totalaccounts; i++))
    do
      tuserval=$(sudo head -n $i /tmp/expirelist.txt | tail -n 1)
      username=$(sudo echo $tuserval | cut -f1 -d:)
      userexp=$(sudo echo $tuserval | cut -f2 -d:)
      userexpireinseconds=$(( $userexp * 86400 ))
      todaystime=$(date +"%s")
      if [[ $userexpireinseconds -ge $todaystime ]]
      then
        timeto7days=$(( $todaystime + 604800 ))
        if [[ $userexpireinseconds -le $timeto7days ]]
        then
          echo $username "is going to expire in 7 Days"
        fi
      else
        echo $username "account has expired"
      fi
    done
    sudo rm /tmp/expirelist.txt
EOF
done

Very close, but the differences really matter! Note, in particular, that the end marker EOF is in column 1 and not indented at all.

Advertisement