How can you expect 2 matches in 1 line
expect "New password*" | "Retype"
send "something\r
You can use -re flag to enable the regular expression support.
expect -re "New password*|Retype"
send "something\r"
The easiest way of doing this is to switch to using the other form of expect:
expect {
"New password*" {}
"Retype" {}
}
send "something\r
The {} can be full scripts if you need to respond differently according to what sort of things happen. The exp_continue command is useful if you want to respond to something and keep on waiting:
expect {
"New password*" {
send "$thepassword\r"
exp_continue
}
"Retype" {
send "$thepassword\r"
exp_continue
}
"thepromptyouexpectafterwards" {}
}
send "something else\r
Related
I wish to check whether a path given is exists or is a directory in another site server in Perl. My code is as below.
my $destination_path = "<path>";
my $ssh = "usr/bin/ssh";
my $user_id = getpwuid( $< );
my $site = "<site_name>";
my $host = "rsync.$site.com";
if ($ssh $user_id\#$host [-d $destination_path]){
print "Is a directory.\n";
}
else{
print "Is not a directory.\n";
}
I am sure my code is wrong as I modify the code according to bash example I see from another question but I have no clue how to fix it. Thanks for everyone that helps here.
[ is the name of a command, and it must be separated from other words on the command line. So just use more spaces:
$ssh $user\#$host [ -d $destination_path ]
To actually execute this command, you'll want to use the builtin system function. system returns 0 when the command it executes is successful (see the docs at the link)
if (0 == system("$ssh $user\#$host [ -d $destination_path ]")) {
print "Is a directory.\n";
} else {
print "Is not a directory.\n";
}
Accessing the remote file system through SFTP:
use Net::SFTP::Foreign;
$sftp = Net::SFTP::Foreign->new("rsync.$site.com");
if ($sftp->test_d($destination_path)) {
"print $destination_path is a directory!\n";
}
I have an expect command
expect "~]#" { send "virsh list --all\r"}
and the output would be
[root#lht1oneems-unit0 ~]# virsh list --all
Id Name State
----------------------------------------------------
399 lht1duplexvm-0 running
- rhelvm shut off
I want to use $expect_out(buffer) and have an if statement to do something if it finds running and do something else if not.
how can I parse into the result of $expect_out(buffer)?
expect "~]#"
send "virsh list --all\r"
# I assume another prompt follows this
expect "~]#"
if { [regexp {running} $expect_out(buffer)] } {
do-something-for-running-process
} else {
do-something-for-no-running-process
}
You could also do
if {[string first "running" $expect_out(buffer)] >= 0} {
I've got a switch case like this:
def someString = 'hello1234bla'
// ...
switch (someString) {
case {it.contains('1234')}:
doSomething()
break
case {it.contains('2468')}:
doSomethingElse()
break
default:
throw new Exception("ERROR: Number not found")
break
}
This seems to be quite a lot of code for something so seemingly simple. All I want is to have different functions be executed when someString contains a specific substring. Is there no simpler way to do this, apart from maybe an if-else cascade?
This is pretty close to what the comments above suggest, but I'll write out a working example with indentation etc and perhaps it will be a bit more readable:
def someString = "hello1234bla"
def found = [
'1234': { println "do something" },
'2468': { println "do something else" }
].find { pattern, action ->
if (someString.contains(pattern)) { action(); true }
else false
}
if (!found) throw new Exception("ERROR: Number not found")
this executes the first matching action and throws an exception if no matches were found. If you need to execute an action for every match, replace the find call with a findAll call.
Another way of executing code based on a pattern in the string is the groovy String eachMatch method:
def someString = "hello1234blae"
someString.eachMatch(/1234/) { println "do something" }
someString.eachMatch(/2468/) { println "do something else" }
which uses regular expressions and runs the closure (the block in the curlies after the eachMatch call) once for every match. Thus:
someString.eachMatch(/e/) { println "runs twice" }
on the above string would execute twice as there are two 'e' characters in the string.
Have a simple groovy script as follows (terribly formatted):
import com.santaba.agent.groovyapi.expect.Expect
def hostname = hostProps.get("system.hostname")
cli = Expect.open(hostname, "user", "pass")
cli.expect("*** Welcome to pfSense ")
cli.send("8\n")
cli.expect("root(1): ")
cli.send( "relayctl show hosts\n" )
cli.expect("root(2): ")
cli.before().eachLine { line ->
if ( line =~ /host/ ) {
tokens = line.split(/\s+/)
println tokens[5]
}
}
cli.send("exit\n")
cli.close()
What I'm unable to do is to pass in the PORT I'd like for it to SSH on, for example: 8331.
Is it possible to achieve this? Thanks!
It looks like you can send in the port number as part of the .open call:
cli = Expect.open(hostname, 8331, 5)//port 8331, 5 connection retries
Should be able to figure the rest of the commands from the logic monitor docs
I'm trying to make a web server whose requests are farmed out to a set of interpreters hidden behind open2(), based on which 'device' is indicated in the cgi parameters.
The trouble is, I want it multi-threaded but the hash I'm using to try to keep track of the event queue relating to each device doesn't remember the new device created for each request: the server below only prints this sort of thing:
Did not find default-device in (alreadyThere)...
Added default-device with Sun Oct 27 20:43:35 2013 to alreadyThere, default-device
Now... does (alreadyThere, default-device) persist for the next request?
Here is the script:
#!/usr/bin/perl -w
use strict;
use threads;
use threads::shared;
use base qw(Net::Server::HTTP);
our $monkeys = shared_clone({ alreadyThere => { 'a' => 'b' } });
sub process_http_request {
require CGI;
my $cgi = CGI->new;
my $device = $cgi->param('device') || 'default-device';
print "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n<pre>";
unless (exists $monkeys->{$device}) {
print "Did not find $device in (".join(", ", sort keys %$monkeys).")...\n";
lock $monkeys;
unless (exists $monkeys->{$device}) {
my $t = localtime;
$monkeys->{$device} = $t;
print "\nAdded $device with ".$t." to ".join(", ", sort keys %$monkeys);
} else {
print "\nSurprise device... ".$device;
}
} else {
print "\nFound device... ".$device;
}
print "\nNow... does (".join(", ", sort keys %$monkeys).") persist for the next request?</pre>";
}
__PACKAGE__->run(port => 8080);
It's not the $t bit - that was previously shared_clone({ id => $t }), but I'm darned if I can see why $monkeys never seems to update.
The different requests are served by different processes, not threads.
Net::Server doesn't have a multi-threaded "personality"[1], so you're going to have to use a different sharing mechanism.
Notes:
"in the near future, we would like to add a 'Thread' personality"
Building on Ikegami's answer, I'm trying with this additional code to fake a 'threaded' personality with some success (and some problems with 'open3' misbehaving):
sub default_server_type { 'Single' }
sub loop {
my $self = shift;
while( $self->accept ){
async {
$self->run_client_connection;
};
last if $self->done;
}
}
a) Is there any reason to use Net::Server::HTTP instead of the higher level and easier to use Plack?
b) I've had to solve a problem not unlike this one recently, and settled on using event-based httpd with AnyEvent (or higher abstraction, Coro). There's Net::Server::Coro if you need a drop-in replacement for your code, or even a plethora of canned AnyEvent-based httpds like Twiggy, Feersum, etc.