Best way to run an entire script via ruby -e - ruby

I've been wanting to run some ruby scripts on remote computers (in a bash shell)
I could create a sequence of bash commands of ruby -e "<command>", but some of these scripts are over 100 lines.
ruby -e with a HEREDOC or %{} & eval() doesn't work well with the mixture of single and double quotes.
Is there a better way to attempt this?
Edit:
The protocol being used is Apple Remote Desktop, which executes these commands in the scope of the remote shell.

If I understand you correctly, you want to run local ruby script on remote machine via SSH or similar protocol. If the script is non-interactive (i.e. doesn't require any user input), you could create it locally and deliver through stdin.
In other words, first write the script and save it locally as, say, foo.rb. Then:
ssh remotehost ruby < foo.rb
That with start the SSH session and execute the remote ruby interpreter. With no arguments, the ruby interpreter executes commands from standard input, and thus we feed SSH with the program on stdin.

As I also want to run ruby scripts via ARD (which I don't think can embed a ctrl-D), I first thought you could combine joraff's solution (to his own problem) with Kelvin's:
cat << ENDOFSCRIPT | ruby
#Here be code ...
ENDOFSCRIPT
Which saves creating/deleting a file.
But there's an even better way:
It turns out (duh) that ARD embeds an EOF or just otherwise terminates what it sends in such a way that you can simply do:
ruby
#Paste whole script here
Works at least in ARD 3.6.1. Win!

This worked:
cat << 'EOF' > /tmp/myscript.rb
# ruby script contents go here. any syntax is valid, except for your limit string (EOF)
EOF
ruby /tmp/myscript.rb;
rm /tmp/myscript.rb;
Since this isn't relying on how an interpreter binary handles stdin-style commands, it will work for most other languages as well (python, perl, php).

Why not send the script over first?
scp foo.rb remotehost:
ssh remotehost "ruby foo.rb"
You could even clean up the file after:
ssh remotehost "rm foo.rb"

Related

Writing Automated scripts to configure device

My requirement is like this:
I need to log in to a remote device (say Router/switch) and execute following commands.
telnet xx.xx.xx.xx
//give password here
sys
interface g x/x/x
shut
desc free-port
exit
There are Hundreds of devices for which I cannot waste time doing above damn thing 100 times. I need to write a automated script which does it. so My questions are as follows:
I use Windows system, so What is the best scripting language to be used : Ruby / shell script / perl ? (I was formerly ROR Developer, so i know Ruby, Linux terminal. Now I am working in networking domain. )
What I thought was : Put all Devices into an array and using for loop, call devices one by one and execute above said commands.
I don't have knowledge of scripting, so please guide me further. I don't know where to start from.
Step 1: decide the file structure of your program.
For example, this is the simplest structure
if_admin/
|--config.yml
|--run.rb
Step 2: write a config file or a bunch of config files that contain the different parts of the commands you need to run on the targets.
For example, you can use a yaml file like this:
xx.xx.xx.xx:
password: s3cret
router-shelf: x
slot: x
port: x
yy.yy.yy.yy:
...
Step 3: implement what you want to do
require 'yaml'
require 'net/telnet'
config = YAML.load_file('./config.yml')
config.each do |host, conf|
telnet = Net::Telnet.new('Host' => host)
telnet.login(conf['password'])
telnet.puts <<-CMD
sys
interface g #{conf['router-shelf']}/#{conf['slot']}/#{conf['port']}
shut
desc free-port
CMD
telnet.close
end
If you can use expect script , you are in luck.
#!/usr/bin/expect
set timeout 60
set cmds [list "ssh host1 ..." "ssh host2 ..." "ssh host3 ..."]
foreach cmd $cmds {
spawn -noecho bash -c $cmd
expect {
-re "password" {
exp_send "$env(PASS_WORD)\"
exp_continue
}
eof { wait } ; # at this time the last spawn'ed process has exited
}
}
Here is the rough idea of above script :-
set cmds [list.... will be used as list to store set of commands.
foreach will iterate though those commands
spawn will spawn process for each of the command. you can write multiple command with single telnet in bash, just break down commands using \ (backslash) so it is easily readable and extendable.
expect block will pass password whenever it encounter certain regex.
eof will wait till all commands in spawn process are finish.
set timeout -1 will keep loop running. i think default time for expect script is 10secs.
You can create one more foreach loop for host-list.
I think this will be enough to get you started for your automation process.
As to the question of "What is the best scripting language to be used", I would say go with one that does what you need and one that you're comfortable with using.
If you want to go with Perl, one module that you could use is Net::Telnet. Of course, you'll need Perl itself. I'd recommend using Strawberry Perl, which should already have Net::Telnet installed.
Another possible route is to use putty, which is a SSH and telnet client. You could combine that with TTY Plus, which provides an interface that uses tabs for different putty sessions. And it lets you issue commands to multiple putty sessions. This is one possibility that wouldn't involve a lot of code writing.

how to script commands that will be executed on a device connected via ssh?

So, I've established a connection via ssh to a remote machine; and now what I would like to do is to execute few commands, grab some files and copy them back to my host machine.
I am aware that I can run
ssh user#host "command1; command2;....command_n"
and then close the connection, but how can I do the same without use the aforememtioned syntax? I have a lot of complex commands that has a bunch of quote and characters that would be a mess to escape.
Thanks!
My immediate thought is why not create a script and push it over to the remote machine to have it run locally in a text file? If you can't for whatever reason, I fiddled around with this and I think you could probably do well with a HEREDOC:
ssh -t jane#stackoverflow.com bash << 'EOF'
command 1 ...
command 2 ...
command 3 ...
EOF
and it seems to do the right thing. Play with your heredoc to keep your quotes safe, but it will get tricky. The only other thing I can offer (and I totally don't recomend this) is you could use a toy like perl to read and write to the ssh process like so:
open S, "| ssh -i ~/.ssh/host_dsa -t jane#stackoverflow.com bash";
print S "date\n"; # and so on
but this is a really crummy way to go about things. Note that you can do this in other languages.
Instead of the shell use some scripting language (Perl, Python, Ruby, etc.) and some module that takes care of the ugly work. For example:
#!/usr/bin/perl
use Net::OpenSSH;
my $ssh = Net::OpenSSH->new($host, user => $user);
$ssh->system('echo', 'Net::Open$$H', 'Quot%$', 'Th|s', '>For', 'You!');
$ssh->system({stdout_file => '/tmp/ls.out'}, 'ls');
$ssh->scp_put($local_path, $remote_path);
my $out = $ssh->capture("find /etc");
From here: Can I ssh somewhere, run some commands, and then leave myself a prompt?
The use of an expect script seems pretty straightforward... Copied from the above link for convenience, not mine, but I found it very useful.
#!/usr/bin/expect -f
spawn ssh $argv
send "export V=hello\n"
send "export W=world\n"
send "echo \$V \$W\n"
interact
I'm guessing a line like
send "scp -Cpvr someLocalFileOrDirectory you#10.10.10.10/home/you
would get you your files back...
and then:
send "exit"
would terminate the session - or you could end with interact and type in the exit yourself..

Can i automate a shellscript that will run a python file which asks for user input?

I know how to run shell scripts pretty easily.
I would have my file say:
#!/bin/zsh
python somefile.py
but the file, somefile in this case requires an input. example:
What is the password?
Can you write a script which will enter that password, or have pause while it waits for input?
My goal overall, is to run a tunneling python script to build a connection and watch a port, pull some data through the tunnel, and then close the python script.
Ideally: I want to have this shellscript option somefile.py in an alternate terminal, as i dont know if i can just no-hup until it is no longer needed then kill the process.
First thing is first. Can you have script which will do something like:
#!/bin/zsh
python somefile.py
echo admin12345
or something similar to auto enter info?
Assuming the python script reads from stdin, just do "echo admin12345 | somefile.py".
Usually, however, that's not the case, and scripts that read passwords will want to read from a terminal, not just any stdin.
In that case, look into "expect".
It worked for me with java and python examples:
#!/bin/bash
echo "1234" | python somefile.py
Just give some permissions to your script chmod +x yourscript.sh, and run it ./yourscript.sh.

How do I pass variables from ruby to sh command

I have a rake task that runs, quite a lot of code. At the end, I need to use sftp and ssh to do some stuff. At the moment I'm unable to automate it. Is there a way to pass to stdout?
This seems like a simple question but I can't find the answer anywhere
#some ruby code
#more ruby code
sh "sftp myuser#hots" #this opens the sftp console
sh "put file" #this doesn't get run until sftp is exited
sh "put another_file" #neither does this
#more ruby code
sh "ssh host" # opens the ssh console
sh "some_action_on_host" # this doesn't get run until ssh is exited
I know there will be ways of doing sftp and ssh using ruby but ideally I just want to be able to pipe variables and commands into the console
So you want to run sftp and send a series of commands to it? How about something like:
sftp = IO.popen("sftp myuser#hots", "w+")
sftp << "put file\n"
sftp << "put another file\n"
sftp.flush # make sure to include this
If you don't want to use ruby, then you may want to enclose your shell commands into ` (backtick characters). This string will be passed to Kernel.` method. This method execute the text as an OS shell command and returns the command's output as a string, e.g.:
`ls`
Alternative syntax to ` is %x[]. This way you can write any bash script:
%x[sftp myuser#hots <<COMMAND
put #{file}
quit
COMMAND]
Please note that this syntax support ruby expressions interpolation using #{...} syntax (similar to double-quoted string literals).

Auto SSH and execute script

I have roughly 12 computers that each have the same script on them. This script merely pings all the other machines, and prints out whether the machine is "reachable" or "unreachable". However, it is inefficient to login to each machine manually using ssh to execute this script.
Suppose I'm logged into node 1. Is there any way to for me to login to node 2-12 automatically using SSH, execute the ping script, pipe the results to a file, logout and proceed to the next machine? Some kind of bash shell script?
I'm afraid I'm at a loss here since I haven't had experience with shell-scripting before.
Since the script is on the other machines, you can just have ssh run the command for you there:
ssh $hostname my_script >> results_file
When you specify a command like that, it's executed instead of the login shell.
I'll leave it up to you to figure out how to loop over hostnames!
One trick you'll need to use is setting up pre-authorized keys for each host. Then you can run a script on one host, running something like 'ssh hostname command > log.hostname'
This script might be what you are looking for: It allows you to execute one command (which can be your script) on multiple remote machines via ssh. It's a simple script with bash source available, so you should be able to customize it to your needs:
http://www.heinzi.at/projects/upgradebest.sh/
Yes you can
You need actually 2 small scripts as following:
remote_ssh.sh ( which takes as first argument the name of the machine and the rest of the arguments are your script that you want to execute with his own arguments)
Example : remote_ssh.sh node5 "echo hello world"
remote_ssh.sh as following:
#!/bin/bash
ALL_ARG=$#
FST_ARG=$1
REST_ARG=${ALL_ARG##$FST_ARG}
echo "Executing REMOTE COMMAND ON $FST_ARG"
/usr/bin/ssh $FST_ARG bash execute_ssh_command.sh $FST_ARG pwd $REST_ARG
execute_ssh_command.sh as following :
#!/bin/bash
ALL_ARG=$#
FST_ARG=$1
DIR_ARG=$2
REM_ARG="$1 $2"
REST_ARG=${ALL_ARG##$REM_ARG}
cd $DIR_ARG
$REST_ARG
of course you have to get this 2 scripts in your path of all your nodes ( maybe ~/bin/ )
Hope that it's helpful

Resources