Telnet Session using Expect Module fails to send command ctrl+A - perl

I am trying to connect to switch which is signaling point switch.
I need to execute the below commands to get to login terminal.
telnet IP Port
Send CTRL+A
Get Prompt ">"
Send command login:uid=user.
Requests for Password provide password.
Gets terminal ">"
Then I have to continue executing some commands to go further, but my problem I am facing an issue while sending CTRL+A.
When I send "ctrl+A" using Expect it just prints "^A" and waits doesn't provide me the terminal.
So, I modified the script by changing the command to "ctrl+A\n" which gives me the terminal but with new line on my next terminal prompt.
Like the below output:
^A
^A
^A
>
wait's here at next line.
which fails to match my next command regular expression ">" and doesn't send the login name.
Can somebody tell me why my first command "^A" fails to get me terminal? And why the command was executed three times before I get the terminal?
I manual scenario it works fine for single ctrl+A
My Sample code:
use Expect;
my $exp = Expect->spawn("telnet 10.10.1.35 2020");
$exp->expect($timeout,
[ qr/]'./ => sub {my $exp = shift;
$exp->send("\cA\n");
} ]
);
$exp->expect($timeout,
[ qr/>/ => sub { my $exp = shift;
$exp->send("login:uid=user\n");
} ]
);
$exp->expect($timeout,
[ qr/Enter Password :/ => sub { my $exp = shift;
$exp->send("xxx\n");
} ]
);
Thank you,
Pradeep.

Try With send "\01"
Please consult for more info
http://expect.sourceforge.net/FAQ.html#q54
I like to enter most control characters literally - since the resulting script is more readable. However, your editor has to allow this. For example, suppose you want to send a Control-A. Conventionally, most editors display this as ^A, but you can't just enter ^ and A. (This will just send those two characters.) Most editors have some simple quoting mechanism that lets you enter the next character literally. For example, using emacs, I can enter ^Q^A and that will add the single character ^A.
Alternatively, Tcl provides a way of encoding using octal or hex. The octal encoding mechanism is less error-prone than hex so I'll demonstrate using octal. For example, since ^A has the octal value 1 in ASCII, to send a ^A:
send "\01"

Related

How to simulate multiple enter key press of batch file execution cmd or windows powershell?

I have batch file which I want to execute, during execution it asks for user input twice to press enter key. I want to skip this completely either by simulating the enter key press or by somehow completely overcoming it.
Edit : I can't edit the bat file to skip the program asking for user input
I have tried echo | <yourfinecommandhere> but this just simulates one enter key press. I am unable to simulate multiple enter key press
In cmd simply group multiple echos. For example this will print 2 newlines to the pipe
(echo[& echo[) | command
echo( is the most reliable way to print a new line in cmd, but in this case echo[ is probably better. Space is significant here so there must be no space after [
In PowerShell it's easier. For example to print 3 newlines use
"`n`n`n" | command
Actually the above will print 4 new lines, because there's an implicit new line after the string. But that won't affect the output. If you want exactly 3 new lines then use
Write-Output -NoNewline "`n`n`n" | command

How to write a test to confirm that a perl script waits (or doesn't wait) for interactive user input (based on supplied options)

I have a perl script for which I would like to write a few tests. If the perl script gets supplied a specific option, the user is allowed to paste or type out multi-line input and end their input using control-d.
These are the tests I want to write:
The script (when an interactive flag is supplied) waits for (multiple lines of) input on STDIN until the user hits control-d
[this test is already implemented - but provided for completeness] The script (when a flag is supplied that indicates a redirect/pipe) consumes all input on STDIN and does not wait for control-d
The script (when no input flag is provided [interactive or redirect]) does not wait for interactive user input
Test 1 toy example
I wrote a test for test 1 that confirms input was received (it works by the parent test script printing to the child's input handle and the child modifies and prints that input back out), but that test doesn't wait for an end of input signal (e.g. control-d) (which I don't know how to send anyway). So in other words, I can confirm it receives input, but I don't know how to confirm that it waits for the user to intentionally end the input entry. I.e. How do I know that the input consumption won't stop until the user types control-d?
Here's what I have so far for test 1. I wrote a 3rd little IO::Pipe::Consumer module to be able to send input to the child process that I'm testing and I wrote a toy example of the script that allows input on STDIN from a tty.
Here is a toy version of the script I'm testing:
>perl -e 'while(<STDIN>){print("*$_")}'
test
*test
^d
>
And here is the toy test code (that I want to improve) for the above script:
>perl -e '
use IO::Pipe::Consumer;
$obj = new IO::Pipe::Consumer;
$si = $obj->getSubroutineConsumer(
sub { while(<STDIN>) print("*$_") } }
);
print $si "test\n"
'
*test
>
I thought the parent would have to print an EOF (e.g. like what you get from "control-d") to end the input in the test, but the test ends immediately even though I'm not sending any such end-of-input character. I can see that it's getting, modifying, and printing the input. Is that sufficient to confirm that the script will wait for user input (and that the user will be able to intentionally end the input) or is there something else I should do to confirm it waits for all user input until the user intends to end it?
Test 2 - done
Test 3 toy - don't know how to write it...
Even if modified input spit back out is sufficient proof of "waiting for input" for test 1, I also wish to test that a script doesn't consume input on STDIN when no input option (interactive or redirect) is provided - but since it doesn't seem to wait even when I do send it input without an end-of-input signal, how would I test that the script wouldn't hang waiting for input? Note, the script has other options for consuming redirected or piped input, so my intent is specifically to know if it's waiting on input from the tty. All of the STDIN consumption options (whether from the tty or via redirect/pipe) are optional, which is why I want to write these tests.
My manual testing shows everything works as intended. I would just like some tests to assure that behavior for the future.
IO::Pipe::Consumer
I feel like the thing I'm missing is not relevant to IO::Pipe::Consumer, so WRT that, I'll just describe it instead of paste in 30 or so lines of code... All it does is it sets a pipe to the child's STDIN and gives that handle back to the parent for it to print to. I haven't put it on cpan. I'm just experimenting to see if I can use it to write these tests.
IO::Pipe::Consumer is basically the opposite of IO::Pipe::Producer (a module I published on cpan looong ago, say 2001-ish, when I was new to perl, or programming for that matter). The main difference, aside from swapping STDIN for STDOUT and Reader with Writer (and vice versa), is that the open is open(STDIN,"<",\${$stdin_pipe}).
I thought the parent would have to print an "end-of-input" (e.g. "control-d") character to end the input in the test,
Ctrl-D doesn't produce an "end of input character"; it causes the terminal to return EOF.
I don't know what IO::Pipe::Consumer is —it's not on CPAN— but I presume it creates a pipe. Exiting the program causes the writer end of the pipe to be closed and thus cause the reader end to return EOF.
is there something else I should do to confirm it waits for all user input until the user intends to end it?
<> reads until one of the following things happen:
A line feed is encountered (returning what was read including the line feed)
EOF is encountered (returning what was read up to an including the line feed)
An error is encountered (returning false).
You can confirm it waits by putting sleep statements between what you send. Be aware that buffering may interfere.

Perl interface with Aspell

I am trying to identify misspelled words with Aspell via Perl. I am working on a Linux server without administrator privileges which means I have access to Perl and Aspell but not, for example, Text::Aspell which is a Perl interface for Aspell.
I want to do the very simple task of passing a list of words to Aspell and having it return the words that are misspelled. If the words I want to check are "dad word lkjlkjlkj" I can do this through the command line with the following commands:
aspell list
dad word lkjlkjlkj
Aspell requires CTRL + D at the end to submit the word list. It would then return "lkjlkjlkj", as this isn't in the dictionary.
In order to do the exact same thing, but submitted via Perl (because I need to do this for thousands of documents) I have tried:
my $list = q(dad word lkjlkjlkj):
my #arguments = ("aspell list", $list, "^D");
my $aspell_out=`#arguments`;
print "Aspell output = $aspell_out\n";
The expected output is "Aspell output = lkjlkjlkj" because this is the output that Aspell gives when you submit these commands via the command line. However, the actual output is just "Aspell output = ". That is, Perl does not capture any output from Aspell. No errors are thrown.
I am not an expert programmer, but I thought this would be a fairly simple task. I've tried various iterations of this code and nothing works. I did some digging and I'm concerned that perhaps because Aspell is interactive, I need to use something like Expect, but I cannot figure out how to use it. Nor am I sure that it is actually the solution to my problem. I also think ^D should be an appropriate replacement for CTRL+D at the end of the commands, but all I know is it doesn't throw an error. I also tried \cd instead. Whatever it is, there is obviously an issue in either submitting the command or capturing the output.
The complication with using aspell out of a program is that it is an interactive and command-line driver tool, as you suspect. However, there is a simple way to do what you need.
In order to use aspell's command list one needs to pass it words via STDIN, as its man page says. While I find the GNU Aspell manual a little difficult to get going with, passing input to a program via its STDIN is easy enough and we can rewrite the invocation as
echo dad word lkj | aspell list
We get lkj printed back, as due. Now this can run out of a program just as it stands
my $word_list = q(word lkj good asdf);
my $cmd = qq(echo $word_list | aspell list);
my #aspell_out = qx($cmd);
print for #aspell_out;
This prints lines lkj and asdf.
I assemble the command in a string (as opposed to an array) for specific reasons, explained below. The qx is the operator form of backticks, which I prefer for its far superior readability.
Note that qx can return all output in a string, if in scalar context (assigned to a scalar for example), or in a list when in list context. Here I assign to an array so you get each word as an element (alas, each also comes with a newline, so may want to do chomp #aspell_out;).
Comment on a list vs string form of a command
I think that it's safe to recommend to use a list-form for a command, in general. So we'd say
my #cmd = ('ls', '-l', $dir); # to be run as an external command
instead of
my $cmd = "ls -l $dir"; # to be run as an external command
The list form generally makes it easier to manage the command, and it avoids the shell altogether.
However, this case is a little different
The qx operator doesn't really behave differently -- the array gets concatenated into a string, and that runs. The very fact that we can pass it an array is incidental, and not even documented
We need to pipe input to aspell's STDIN, and shell does that for us simply. We can use a shell with command's LIST form as well, but then we'd need to invoke it explicitly. We can also go for aspell's STDIN by means other than the shell but that's more complex
With a command in a list the command name must be the first word, so that "aspell list" from the question is wrong and it should fail (there is no command named that) ... except that in this case it wouldn't (if the rest were correct), since for qx the array gets collapsed into a string
Finally, apsell nicely exposes its API in a C library and that's been utilized for the module you mention. I'd suggest to install it as a user (no privileges needed) and use that.
You should take a step back and investigate if you can install Text::Aspell without administrator privilige. In most cases that's perfectly possible.
You can install modules into your home directory. If there is no C-compiler available on the server you can install the module on a compatible machine, compile and copy the files.

PowerShell console host displays strings inconsistently

When I run this in PowerShell ISE, both strings are displayed identically.
When I run it in the console host, string $a is missing the empty line.
Why is that, and can I work around it?
I want to format blocks of text without using `n
$a = "there should be one emtpy line
between these two lines of text"
$b = "there should be one emtpy line`n`nbetween these two lines of text"
$a
$b
If you type that into the console host, you're correct; it won't work as expected. But if you save it in a file, then it does work as expected (the blank line is preserved).
I believe that this is because of the way the console host is using blank lines to interpret your input, since it needs to detect blank lines to tell when to stop input in some cases.
I don't know enough to know if it's a bug.
Something else that may not be clear is that when you write the way you're assigning it to $a, you're actually inserting CR and LF ("`r`n") when in the ISE host, whereas with $b you're just using LF. In the console host, a LF only is used.
To see that, I like to use [RegEx]::Escape:
[RegEx]::Escape($a)
[RegEx]::Escape($b)
Using this I was able to confirm that using the console host to enter the strings, the second LF is actually not present in the $a string; it's not simply a display issue.

How do I pass a Tcl data structure to Perl with Telnet in between?

I want to telnet into a Cisco router, login and execute a Tcl script that is locally stored in the router's flash. This Tcl script does some processing and should return a nested hash (preferred) or a string that represents a XML document.
Is there a way to map a Tcl nested hash to a Perl nested hash, or to return a string that represents a XML document? Does Expect allow me to do any of the above, and how?
Serialise the data to a common exchange format, e.g. a JSON string.
Have the Tcl program emit JSON. Load the JSON from Perl into a hash.
Cisco routers tend to run old versions of Tcl, and to not have a large range of extension packages available. That means that you're quite restricted in what you can do. Luckily, for the job of producing data that can be collected and parsed by Perl, it's actually fairly straight-forward.
Let's use JSON as the interchange format. (Others are possible too.) Daxim's answer tells you how to parse JSON, but that's quite easy because you're running in a context you can control. How to generate JSON data in that crufty old Tcl? The easiest method is with the subst command — it's been functionally unchanged in Tcl for ages, so you've definitely got it — and a few helper commands. Here's the outline:
proc getFoo {} {
# Some regular Tcl code to get the value
}
proc getFruit {variety} {
# Some regular Tcl code to get the value
}
set someIntValue [expr { 1 + 2 * 3 }] ;# Or whatever...
set jsonTemplate {
{
"foo": [getFoo],
"bar": {
"pears": "[getFruit pears]",
"apples": "[getFruit apples]"
},
"grill": $someIntValue
}
}
puts [subst $jsonTemplate]
OK, caveat time: I've no idea what data you're wanting to receive (“nested hashes” isn't very much to go on). You'll have to add quoting/backslashing where required. Put the procedures before the call to subst (the order of things matters in Tcl).
This expect script should take the file off the router and leave it in /tmp/xferfile.txt. It will need to be modified with the commands that actually produce the file, since I do not have those, I left placeholders for them in the script. You should be able to use Donal's code for that.
It's been a while since I've played with expect and cisco IOS, so bear with me if this needs some debugging on your end.
#!/usr/bin/expect
set timeout 20
set ip [lindex $argv 0]
set user [lindex $argv 1]
set password [lindex $argv 2]
set prompt1 "Router>"
set prompt2 "Router#"
set prompt3 "bash\$"
set ctrld [expr ("d" & 01xF)]
spawn ssh "$user\#$ip"
expect "Password:"
send "$password\r";
# switch to privileged EXEC level
expect $prompt1 { send "enable" }
# ==================================================
# Modify this line for your needs
# ==================================================
expect $prompt2 { send "command to print Tcl hash" }
# Capture output to variable
set results $expect_out(buffer)
# leave EXEC level
expect $prompt2 { send "exit" }
# Command to log out of router
expect $prompt1 { send "exit" }
# Create text file on localhost
spawn "#!/bin/bash"
expect prompt3 {
send "cat > /tmp/xferfile.txt"
sleep 5
send $results
send $crtld
}
expect prompt3 { send "exit" }