I wrote a Perl program where the user should type in a user name. If they enter admin, they should see the message
Welcome, admin!
Otherwise the console output should be
The username is incorrect
Here is my code
use utf8;
print "Username: ";
$username = <STDIN>;
if ( $username eq "admin" ) {
print "Welcome, admin!";
}
else {
print "The username is incorrect.";
}
But whatever the user inputs the program goes on to the else branch.
Why does this happen?
Whenever you are not sure why a comparison fails, make sure you know what's in your variable:
use Data::Dumper;
local $Data::Dumper::Useqq = 1;
print Dumper $variable;
# print Dumper \#array;
# print Dumper \%hash;
like #ikegami suggested, you need to use chomp:
chomp $username;
perldoc -f chomp
The empty <> operator is usually the best choice for input. It will read data from any files named on the command line, or from the keyboard if there were none
Your $username = <STDIN> will read from the keyboard, and if you enter admin and the enter key it will contain "admin\n". So you need to chomp the LF character from the end of the input
You should also use strict and use warnings 'all' at the start of every Perl program
Like this
use strict;
use warnings 'all';
print "Username: ";
my $user_name = <>;
chomp $user_name;
if ( $user_name eq 'admin' ) {
print "Welcome, admin!\n";
}
else {
print "The username is incorrect\n";
}
The comparison never succeed because you don't remove the line feed created by pressing Enter. Use chomp!
As everyone else already mentioned, you have a line feed and chomp will sort that out. In the rare event however where a user perhaps types a space before admin, it will still fail. You can therefore use left and right trim
use strict;
use warnings 'all';
print "Username: ";
my $user_name = <>;
$user_name =~ s/^\s+|\s+$//g;
if ( $user_name eq 'admin' ) {
print "Welcome, admin!\n";
}
else {
print "The username is incorrect\n";
}
which will match admin followed by newline, space or tab before and space or tab after admin.
You are missing to use chomp. When user has entered admin, it translated to admin\n, so we need to remove that \n. chomp is used to remove the $/ variable (line feed character) which is set to mostly \n (new line). $/ is the input record separator, newline by default.
use utf8;
print "Username: ";
$username = <STDIN>;
chomp $username;
if ( $username eq "admin" ) {
print "Welcome, admin!";
}
else {
print "The username is incorrect.";
}
Related
I am using perl expect to enter password in an interactive program. Perl is outputting correct password but setting it something else.
#!/bin/perl
use Expect;
my $hostname = qx! /usr/bin/hostname !;
my $Passwd = `./ensite_passwd solidcore $hostname`;
my $sadminPasswd = quotemeta $Passwd;
chomp $sadminPasswd;
chop $sadminPasswd;
print "password is $sadminPasswd \n\n";
my $sadminPasswd = Expect->spawn("/sbin/sadmin", "passwd")
or die "Cannot spawn /sbin/sadmin $!\n";
$sadminPasswd->expect(300,
[qr/New Password:/ => sub {
my $fh = shift;
$fh->send("${sadminPasswd}\n");
print "sent '${sadminPasswd}'\n";
exp_continue;
}
],
[qr/Retype Password:/ => sub {
my $fh = shift;
$fh->send("p2c4f8j5\n");
#$fh->send("${sadminPasswd}\n");
#print "sent '${sadminPasswd}'\n";
print "sent 'p2c4f8j5'\n";
}
]);
$sadminPasswd->soft_close();
I am getting below output:
swdvssd0046$ sudo perl test.pl
password is p2c4f8j5
New Password:sent 'Expect=GLOB(0x23ae188)'
Retype Password:sent 'p2c4f8j5'
Passwords do not match.
swdvssd0046$
I don't understand 'Expect=GLOB(0x23ae188)' at all.
I know password for this host would be "p2c4f8j5" that's why I have manually entered it in confirm password expect code.
Any idea what am I missing?
use warnings; ... "my" variable $sadminPasswd masks earlier declaration in same scope
Thanks toolic for answer!
I'm trying to compare a string to another.
If it's a JSON structure which contains things, I want to print "contains things".
If it's a JSON structure which doesn't contain thing, I print "empty"
If it something which is not between curly brackets "{}", i print that there's an error.
Here's what I've done :
if($content =~ m/{.+}/){
print "Contains things \n";
} elsif($content eq "{}"){
$job_status{$url}="";
print "empty \n";
} else {
print "Error \n";
}
When I pass "{}" to the variable $content, he does not enter the "elsif", but go to the "else", and throw an error.
I've tried to put "==" instead the "eq" in the if, even though I know it's for numbers. When so, he enters the "elsif", and print "empty", like he should do with the "eq", and throws :
Argument "{}" isn't numeric in numeric eq (==)".
I could use the JSON library but I prefer not.
Thanks for your help !
Bidy
It works for me. Does $content have a newline character? Try chomp $content;.
use warnings;
use strict;
my $content = '{}';
if($content =~ m/{.+}/){
print "Contains things \n";
} elsif($content eq "{}"){
print "empty \n";
} else {
print "Error \n";
}
__END__
empty
I can replicate the behaviour if I add a newline after the {}:
#!/usr/bin/perl
use strict;
use warnings;
my $content = "{}\n";
if($content =~ m/{.+}/){
print "Contains things \n";
} elsif($content eq "{}"){
print "empty \n";
} else {
print "Error \n";
}
It returns "Error", if I replace eq with ==, it returns empty, because both "{}" and "{}\n" are numerically 0. A warning is thrown as you mentioned.
You might try to chomp the $content before processing it.
A top-level JSON thingy can be an object ({...}) or an array ([...]), but you're only checking for one of those. If you merely want to see if it's empty, I'd check the length of the string:
chomp $possible_json;
if( $length $possible_json >= 3 ) { ... }
You might also consider Randal Schwartz's regex for JSON parsing. It doesn't handle everything, but it's often enough for simple things.
I'd probably end up breaking it up:
unless ($content) {print "Error\n"};
$content =~ /{(.*)}/
my $resp = $1;
if ($resp) {
print "Contains Things ($resp)\n";
} else {
print "Empty\n";
}
I am attempting to write a code that will encrypt letters with a basic cyclic shift cipher while leaving any character that is not a letter alone. I am trying to do this through the use of a sub that finds the new value for each of the letters. When I run the code now,it formats the result so there is a single space between every encrypted letter instead of keeping the original formatting. I also cannot get the result to be only in lowercase letters.
sub encrypter {
my $letter = shift #_;
if ($letter =~ m/^[a-zA-Z]/) {
$letter =~ y/N-ZA-Mn-za-m/A-Za-z/;
return $letter;
}
else {
return lc($letter);
}
}
print "Input string to be encrypted: ";
my $input = <STDIN>;
chomp $input;
print "$input # USER INPUT\n";
my #inputArray = split (//, $input);
my $i = 0;
my #encryptedArray;
for ($i = 0; $i <= $#inputArray; $i++) {
$encryptedArray[$i] = encrypter($inputArray[$i]);
}
print "#encryptedArray # OUTPUT\n";
The problem is how you are printing the array.
Change this line:
print "#encryptedArray # OUTPUT\n";
to:
print join("", #encryptedArray) . " # OUTPUT\n";
Here is an example that illustrates the problem.
#!/usr/bin/perl
my #array = ("a","b","c","d");
print "#array # OUTPUT\n";
print join("", #array) . " # OUTPUT\n";
Output:
$ perl test.pl
a b c d # OUTPUT
abcd # OUTPUT
According to the Perl documentation on print:
The current value of $, (if any) is printed between each LIST item.
The current value of $\ (if any) is printed after the entire LIST has
been printed.
So two others ways to do it would be:
#!/usr/bin/perl
my #array = ("a","b","c","d");
$,="";
print #array, " #OUTPUT\n";
or
#!/usr/bin/perl
my #array = ("a","b","c","d");
$"="";
print #array, " #OUTPUT\n";
Here is a related answer and here is documentation explaining $" and $,.
Those spaces in your output from $" (list separator) because you use print "#encryptedArray" to print that array, which equals print join($", #encryptedArray), therefore you could disable them by
local $" = '';
or you could join that #encryptedArray by yourself before you print it, just as suggested by #Matt.
Note that there is no need for such complexity. tr/// - also known as y/// - wil convert the whole string for you. Like this
use strict;
use warnings;
print "Input string to be encrypted: ";
chomp(my $input = <STDIN>);
print "$input # USER INPUT\n";
(my $encrypted = $input) =~ tr/N-ZA-Mn-za-m/A-Za-z/;
print "$encrypted # OUTPUT\n";
I am writing a program that takes numbers from the command line until the user enters a blank line.
Should the user enter something that is neither newline nor numeric, it notifies the user, and continues.
While everything works, I have use warnings turned on, and it doesn't seem to like the second if conditional if the enters something invalid.
Argument "foo" isn't numeric in numeric eq (==) at adder.pl line 25, <STDIN> line 4.
I don't like running the program with this warning. How can I improve my code?
This is my program
#!/usr/bin/perl
use strict;
use warnings;
#declare variable
my $number = 0; #final answer
my $input;
#prompt the user
print "Input some integers, line by line. When you are done, press return to add them up." . "\n";
while (1) {
#get input from user
$input = <STDIN>;
#remove newlines
chomp($input);
#user pnches in newline
if ($input eq '') { #if the answer is new line
#quit the loop
last;
} #end of if statement
#user punches in bad input
elsif ($input == 0 && $input ne '0' && $input ne '') {
#tell the user what happened and how to rectify it
print "Input must be an integer." . "\n";
} # end of elsif statement
else {
chomp($input);
$number += $input;
} # end of else statement
} #end of while
print "Total is: $number\n";
Perl does DWIM very well. It is famous for it.
So, whatever language you have come from - it looks like C - forget about checking for both strings and numbers: a Perl scalar variable is whatever you ask it to be.
That means something like
elsif ($input == 0 && $input ne '0' && $input ne '') {
makes little sense. Anything read from the keyboard is initially a string, but it will be a number if you want. You are asking for $input to evaluate as zero but not to be the literal string 0. That applies to very few strings, for instance 00 or 0e0.
I think this is what you meant to write. Please take a look.
Isn't it clearer without comments?
use strict;
use warnings;
print "Input some integers line by line. When you are done, press return to add them up\n";
my $total = 0;
while (<>) {
chomp;
last unless /\S/;
if (/\D/) {
print "Input must be an integer\n";
next;
}
$total += $_;
}
print "Total is: $total\n";
Since Perl is untyped, and you are using $input as both a number and a string, you get that warning because "foo" isn't a number and "==" is used to compare equality of numbers.
You first need to check to see if $input is a number or not. One suggestion:
if ($input =~ /^\d+$/)
{
$number += $input;
}
else
{
print "Input must be an integer.\n";
}
I am having problem in parsing the output from the text file. I want to add pipe symbol in between the character to do mutliple search similar to egrep, the text file is as follows
service entered the stopped state,critical
service entered the running state,clear
Code:
open(my $data, '<', $Config_File) or die "Could not open '$Config_File"
my $reg_exp;
my $severity;
my #fields=();
while (my $line = <$data>)
{
chomp $line;
if(!$line =~ /^$/)
{
#fields = split "," , $line;
$reg_exp = $fields[0];
$severity = $fields[1];
print $reg_exp;
}
}
#print $fields[0];
#last unless defined $line;
close($data);
expected output
service entered the stopped state|service entered the running state
You are not far off, you just need to actually concatenate the strings. The simplest way would be to push the $fields[0] to an array, and wait until the input is done to print it. I.e.:
my #data;
while (my $line = <$data>) {
next if $line =~ /^$/; # no need to chomp
my #fields = split /,/, $line;
push #data, $fields[0];
}
print join("|", #data), "\n";
I sense that you are trying to achieve something else with this code, and that this is a so-called XY-problem.