I need to create a script which logs into all the servers listed in servers.txt. I want to use password, no passwordless. After logging in, I need to set a variable and perform an if- then- else.  After the work is complete, it should create a file on the local machine, not on the remote one. The (local) file will contain the hostname(s) of the machines where certain process wasn't running.

The general idea is:

while read line
    sshpass -p ******** ssh "mydomain1\admin1"@$line bash -s << EOF
    var=$"(ps -ef | grep http | grep -v grep | wc -l)"
    if (( var > 0 ))
        echo  "$pwd" | sudo -S ps -ef | grep patrol | grep -v grep | awk '{print $2}' | xargs kill
        echo  "$pwd" | sudo -S rm -rf /data/abc /etc/efg 
        #need to create the log on local machine, not on remote machine
        hostname >> /find.txt
        #need to create the log on local machine, not on the remote machine
        hostname >> /agentnotthere.txt
#servers.txt contains server names
done < servers.txt

Obviously lines 5-16 of the above form a here document containing commands to run on the remote host.  In that here document, I have commands hostname >> /find.txt and hostname >> /agentnotthere.txt.  As stated in my introductory paragraph, and again in comments in the code, I want the (remote) hostname to be written to a local file, not a file on the remote machine.  Obviously, a command >> filename command on the remote machine will write to a file on the remote machine.

How can I get my script, which uses ssh to run a few commands on remote machine(s), to write output to a local file based on the results of test(s) performed on the remote machine?

  • 1
    Ok. What's not working?
    – phemmer
    May 29 '18 at 12:14
  • Sudo su and creating the file on local machine.
    – A K
    May 30 '18 at 8:09

I don't think there's an easy way to do what you wanted, meaning writing to separate files on your local host from a script that's executing on a remote machine.

You can easily pipe the output of the script to one local file, though:

ssh host << EOF > output_file              
some commands
to be executed

With that, you can restructure the script so that it executes ssh multiple times (this will increase the ssh overhead, but you can mitigate most of it by using ControlPersist in the ssh config file).

So instead you'll end up with something like this (pseudo-bash):

echo "get the output of var script" | ssh host > var_value
if var read from the file is more than zero; then
  echo "the thing you want" | ssh host >> /find.txt
  echo "the other thing you want" | ssh host >> /agentnotthere.txt

This should suit your use case just fine :)

My two cents about the script itself:

  • Ansible or one of the other configuration management tools is probably better suited to this task instead of writing bash scripts
  • Using SSH passwords instead of key auth is bad from a security standpoint. But I've been in situations where it's impossible to implement that either because of company policy/old embedded stuff that doesn't support it/etc.
  • Instead of using the old ps aux | grep -v grep | grep something boilerplate, you can use pgrep and pkill. They are in standard coreutils, so unless you use really antique systems they should be available on them
  • Can we pass password also? I am looking for the solution to automate. Don't want to give password each time. There has to be a way to automate in the shell script or we can try "expect" to pass password and all.
    – A K
    May 30 '18 at 8:15
  • Yeah, I don't see an issue with that. I used ssh user@host instead of sshpass -p pass ssh user@host in my examples because it's shorter ;) May 30 '18 at 9:32
  • one more thing I have to use </dev/null end of ssh line otherwise loop is ending when it disconnects from ssh :(
    – A K
    May 31 '18 at 10:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.