SSH plus tail -f without key exchange possible?

J

jrpfinch

I would like to tail -f a file on a remote machine over SSH and
process output line-by-line as it comes in. I'm pretty sure this can
be done using Expect and open (FH, "ssh root@remote_machine ... tail -
f |") if you have exchanged keys. ssh will not take a supplied
username and password on the command line, however.

This leaves Net::SSH::perl, which does accept user/pass login, but
AFAIK only lets you issue discrete commands via the '->cmd("ls -ltr")'
method.

Any hints appreciated. Otherwise I'm just going to examine the file
size at discrete intervals and use tail -[some number] to get the
output if the file size has changed. This does not seem to be an
efficient solution.

Many thanks

Jon
 
A

anno4000

jrpfinch said:
I would like to tail -f a file on a remote machine over SSH and
process output line-by-line as it comes in. I'm pretty sure this can

Have you seen the FAQ 'How do I do a "tail -f" in perl?' ?

Anno
 
J

jrpfinch

Have you seen the FAQ 'How do I do a "tail -f" in perl?' ?

Yes I have but don't see how you can combine this with ssh. AFAIK you
can't combine this with Net::SSH::perl because it only returns output
when a command has finished running (i.e. you can only execute
discrete commands). If there is a way, then I would be grateful to
know - I must have overlooked something.
 
X

xhoster

jrpfinch said:
I would like to tail -f a file on a remote machine over SSH and
process output line-by-line as it comes in. I'm pretty sure this can
be done using Expect and open (FH, "ssh root@remote_machine ... tail -
f |") if you have exchanged keys.

You don't even need the Expect if you have exchanged keys. Just the piped
open is sufficient. If you do need to provide a password, maybe Expect can
be arranged to handle that, but I haven't done it to prove it can be done.
ssh will not take a supplied
username and password on the command line, however.

When I start ssh from a perl script, it will read bypass stdin/stdout and
will ask (and receive) a password directly from the controlling tty. Not
the same thing as the command line, but perhaps good enough.
This leaves Net::SSH::perl, which does accept user/pass login, but
AFAIK only lets you issue discrete commands via the '->cmd("ls -ltr")'
method.

Since you don't *want* to issue a discrete command, then don't
use ->cmd(). Use the advanced methods, maybe either socket or
register_handler.

Once you call login, the $ssh object gets re-blessed into a different
package. If you can't figure out how to use those more advanced features,
then figure out what package that is, and go look at that package's
implementation of cmd to see how cmd itself uses those more advanced
features.

Xho
 
J

Jorgen Grahn

jrpfinch said:
I would like to tail -f a file on a remote machine over SSH and
process output line-by-line as it comes in. I'm pretty sure this can
be done using Expect and open (FH, "ssh root@remote_machine ... tail -
f |") if you have exchanged keys.

You don't even need the Expect if you have exchanged keys. Just the piped
open is sufficient. [...]

Yes; I do it regularly. If you can place the burden on the user (i.e.
say "make sure you can ssh into 'remote_machine' without password
prompt, or be prepared to enter one manually every time") then it
works well.

Also note that (Open)ssh is pretty configurable. A user can say things
like "whenever I log in to a host whose name matches this pattern, I
want to login as root, and/or use this key". You may not need to
hardcode "root" as in the example above.

/Jorgen
 
J

jrpfinch

Since you don't *want* to issue a discrete command, then don't
use ->cmd(). Use the advanced methods, maybe either socket or
register_handler.

Thank you - register_handler was just the trick.

I based my code on eg/remoteinteract.pl supplied with the
Net::SSH::perl source.
 
J

jrpfinch

I am come across a further problem. Currently my code looks like
this:

[snip]
{
$dieOutput = undef;
local $SIG{ALRM} = sub { die "Timed out" };
alarm 10;
eval("\$conn = Net::SSH::perl -> new ('$host', protocol => 2);".
"\$conn->login('$user','$password')");
alarm 0;
$dieOutput = $@ if $@;
}

$conn->register_handler("stdout", sub { #do stuff# })

$conn->cmd("tail -f somefile");

# part 2 - when connection dies/terminated do some more stuff

The problem with this is that if the script terminates for some
reason, I am left with an orphan tail -f process on the remote
machine. Also, I would like to be able to put something in the
register_handler to kill the connection if a certain line appears in
somefile.

Any ideas? Or am I going about this in completely the wrong way? I
would like to avoid Net::SSH2 if possible, as this would require a
rewrite and I am unable to compile the libssh2 libraries on Solaris 9.
 
X

xhoster

jrpfinch said:
I am come across a further problem. Currently my code looks like
this:

[snip]
{
$dieOutput = undef;
local $SIG{ALRM} = sub { die "Timed out" };
alarm 10;
eval("\$conn = Net::SSH::perl -> new ('$host', protocol => 2);".
"\$conn->login('$user','$password')");
alarm 0;
$dieOutput = $@ if $@;
}

$conn->register_handler("stdout", sub { #do stuff# })

$conn->cmd("tail -f somefile");

# part 2 - when connection dies/terminated do some more stuff

The problem with this is that if the script terminates for some
reason, I am left with an orphan tail -f process on the remote
machine.

I suspect, but do not know for certain, that once the file grows to the
point that the remote tail -f has filled up it's pipe buffer, it will die.
If the file grows slowly, that might take a while.
Also, I would like to be able to put something in the
register_handler to kill the connection if a certain line appears in
somefile.

How about just dying inside the register_handler? It should kill the
client end of the connection, at least.

I'd consider writing a Perl script to be used in the place of tail -f on
the remote machine. You can have the Perl script quite on the remote side
when it sees the qualifying line. It could also handle the time-out.

http://groups.google.com/group/comp..._frm/thread/4af4a659423b5b6e/42b07d4640c02b15
Any ideas? Or am I going about this in completely the wrong way? I
would like to avoid Net::SSH2 if possible, as this would require a
rewrite and I am unable to compile the libssh2 libraries on Solaris 9.


Xho
 
X

xhoster

Some said:
I suspect, but do not know for certain, that once the file grows to the
point that the remote tail -f has filled up it's pipe buffer, it will

its, not it's.
I'd consider writing a Perl script to be used in the place of tail -f on
the remote machine. You can have the Perl script quite

quit, not quite.

Sigh.

I used to think Perl was my first language. Now I'm starting to think it
is my only language.

Xho
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,120
Latest member
ShelaWalli
Top