Clear already printed values using perl - perl

I need to clear the printed values in perl console window. For an example,
Note: I am developing this in Windows OS.
use strict;
my $mode;
Initialize();
sub Initialize{
print "Enter 1 or 2";
$mode=<STDIN>;
chomp($mode);
check_mode($mode);
}
sub check_mode{
if(($mode!=1) and ($mode!=2)){
print "invalid selection";
Initialize();
}
else{
print "valid selection";
sleep 5;
}
}
While entering wrong selection, I have called the Initialize function, it is printing again. But, what I want is while calling the function it should delete already printed value in the console window and it should print again. Is it possible?
Please give your valuable suggestions.

While you can use the backspace character code "\b" to erase characters on the current line, that has limitations since when the user hits enter it will print a linefeed and your backspace characters won't carry back up to erase the previous line.
See Win32::Console which should allow you to print your prompt at a fixed location and then later overwrite the wrong selection or you can get input a single character at a time using the InputChar method and suppress the newline...

for specific to window os and linux os
system($^O =~ /win/i ? 'cls' : 'clear');

Related

Discarding extra newlines on STDIN in Perl without Term::ReadKey

I've been digging through search engine results and Stack Overflow trying to solve this problem, and I've tried a dozen different "solutions" to no avail. I cannot use Term::ReadKey, as most solutions suggest, due to limitations of my environment.
The existing Perl script does:
my $mode1=<STDIN>;
chomp($mode1);
but many of the prompts don't evaluate the input - for example the user could enter an arbitrary string - but the script only chomps the input and then ignores the contents. Several prompts ask for input but pressing [ENTER] without entering input applies default values.
If the user gets impatient while the script is in a blocking function or checks to see if the terminal is responding by pressing [ENTER], those newline characters advance the script inappropriately when the blocking function ends. I don't want to rely on user training instead of automation, and it seems like there must be an easy obvious solution but I can't seem to dig one up.
It isn't originally my script, and its author admits it was quick-and-dirty to begin with.
The 4-argument select function is a little cryptic to use, but it can tell you, in many cases, whether there is any unread input waiting on an input filehandle. When it is time for your program to prompt the user for input, you can use select to see if there is any extra input on STDIN, and clear it before you prompt the user again and ask for additional input.
print "Prompt #48: are you tired of answering questions yet? [y/N]";
clearSTDIN();
$ans48 = <STDIN>;
...
sub clearSTDIN {
my $rin = "";
vec($rin, fileno(STDIN), 1) = 1;
my ($found,$left) = select $rin,undef,undef,0;
while ($found) {
# $found is non-zero if there is any input waiting on STDIN
my $waste = <STDIN>; # consume a line of STDIN
($found,$left) = select $rin,undef,undef,0;
}
seek STDIN,0,1; # clears eof flag on STDIN handle
}
Is the easy solution to close STDIN?
print "Are you sick of answering questions yet? [y/N] ";
$ans = <STDIN>;
if ($ans =~ /^y/i) {
close STDIN;
# from now on, further calls to <STDIN> will immediately
# return undef and will assign default values
}
...

Perl - How to output all on one line

I'm new to PERL but have picked it up rather quickly as I work in C.
My question seems simple, but for the life of me I cant find a simple answer. Basically I want to print something on the same line as user input
Example
print "Please Enter Here: ";
my $input = <STDIN>;
chomp $input;
print " - You Entered: $input";
Output
Please Enter Here: 123
- You Entered: 123
This is undesired as I want all of this on one line in the terminal window. At the moment it prints the second string on the line below once the user has pressed the enter key. I guess what i'm going to need to do is something with STDIN like ignore the carriage return or newline but I'm not sure.
Desired Output
Please Enter Here: 123 - You Entered: 123
I don't know why this seems to be a complicated thing to google but I just haven't fathomed it, so any help would be appreciated.
Ta
Well, this is interesting...
First, you'd have to turn off terminal echoing, using something like IO::Stty. Once you do that, you could use getc. Note that the getc perldoc page has a sample program that could be used. You can loop until you get a \n character as input.
You can also try Term::ReadKey.
I have never done this myself. I'll have to give it a try, and if I succeed, I'll post the answer.
The Program
Ended up I already had Term::ReadKey installed:
#! /usr/bin/env perl
#
use warnings;
use strict;
use feature qw(say);
use Term::ReadKey;
ReadMode 5; # Super Raw mode
my $string;
print "Please Enter Here: ";
while ( my $char = getc ) {
last if ord( $char ) < 32; # \r? \n? \l?
$string .= $char;
print "$char";
}
ReadMode 0;
say qq( - You entered "$string".);
I realized that, depending how the terminal is setup, it's hard to know exactly what is returned when you press <RETURN>. Therefore, I punted and look for any ASCII character that's before a space.
One more thing: I didn't handle what happens if the user hit a backspace, or other special characters. Instead, I simply punt which may not be what you want to do.
In the end I did:
"\033[1A\033[45C
It uses the code functions for line up and 45 indent and it works. Thanks for all the help though.

Read single characters, and use Return as EOL instead of Ctrl-D in Linux

I'm a beginner to perl, and just started reading user input in my script.
chomp(my $inp = <> );
I have been used to using Return key as the terminator for user input in other languages, and am unsure how to stop reading user input after getting a single key press, or some characters followed by Return key. In perl running on unix, capturing input via the diamond operator, seems to require pressing Ctrl-D for end of input.
My problem is that I'd like to build an interactive menu where user is presented a list and asked to press "A", "B" or "C". Once he presses any of these keys, I'd like to loop according to conditions, without waiting for him to press Ctrl D. How can I get this level of interactive user input in perl? In C, I'd use getch. In Bash, I'd use a read and $REPLY.
I'd also like to know how to use the Return key to terminate user input.
For getting single characters, perldoc mentions:
if ($BSD_STYLE) {
system "stty cbreak </dev/tty >/dev/tty 2>&1";
}
else {
system "stty", '-icanon', 'eol', "\001";
}
$key = getc(STDIN);
if ($BSD_STYLE) {
system "stty -cbreak </dev/tty >/dev/tty 2>&1";
}
else {
system 'stty', 'icanon', 'eol', '^#'; # ASCII NUL
}
print "\n";
Surely in a language like perl, it isnt that difficult?
Edit: It seems like what I was looking for isnt natively available. However, IO::Prompter seems to be the solution.
The diamond operator reads one line in scalar context, and one file in array context. Ctrl-D is EOF, Return is EOL.
Because chomp supplies a list context, you have to break this up:
my $inp = <>;
chomp $inp;
The portable way to read a single keypress is Term::Readkey. See http://learn.perl.org/faq/perlfaq5.html#How-can-I-read-a-single-character-from-a-file-From-the-keyboard-

Net::Telnet using getline() or getlines() not getting all lines

If I telnet using my terminal window to the device and enter show which prints config it prints certain number of lines and -- more -- in the bottom, you can press Return or Space on the keyboard a few times to get the rest of the command until it is all shown on screen, you know how it is.
With
$t->print('show');
Problem is neither
while (my $line = $t->getline()) {
print $line;
}
or
my #lines = $t->getlines(All => 0); # or All => 1
gives me all lines, just the starting few as with the terminal window.
I cant use cmd() or Expect or Net::OpenSSH on that box (the machine where the script runs, im not talking about the device), no gcc and has a crippled package manager. (Read: can't install IO::Pty)
What can I do to get the rest of the output of the command?
If that show you use hasn't an option to turn off its paging, waiting for a keypress after each page, you have to ->print('') at appropriate times, therewith sending the continuation characters.

cygwin seems to be swallowing my carriage returns

I have a perl script that grabs some files from a remote server and I'd like to be able to represent progress. The way I'm trying to do it is like this:
print "\tDownloading comp.reg.binary.sdiff.log...\n";
if(does_file_exist('comp.reg.binary.sdiff.log', #ret)){
$sftp->get("t-gds/log/comp.reg.binary.sdiff.log", $saveDir, sub {
my($sftp, $data, $offset, $size) = #_;
print "\tRead $offset of $size bytes\r";
});
print "\n\tDownloaded.\n";
}else{
print "\tFile not found on server...skipping.\n";
}
However, cygwin seems to swallow carriage returns and doesn't print anything until the last print statement. I doubt it because the script is running too fast, because when I change \r to \n, I can see them print out slowly.
Does anyone have any idea why it's not working the way it should?
Did you remember to set $| to 1 first? Sounds like not.
Your output is probably line-buffered. Try adding $| = 1; to the top of your script. If that works, there are ways to exercise more find-grained control.
Which terminal are you using? If it's not a cygwin-provided pty (such as the rxvt that ships with cygwin) but instead a Windows console, it is possible that perl cannot detect that it's writing to a terminal, and therefore defaults to buffering the output internally until it can write a good-sized chunk out.
Use $| = 1; to suppress this buffering explicitly.