accessing perl scalar variables in () - perl

$a=10
print "$a";
print "${a}";
print "$(a)";
print "$a"; and print "${a}"; work exactly same way, looks like both syntax are supported in perl to print scalar variables, but print "$(a)"; prints strange values , Want to undersand what happens when print "$(a)";

$( is a valid scalar in Perl. It contains the space-separated list of group ids that the current user belongs to.
So print "$(a)" is equivalent to print $( . "a)" and you can expect output like
perl -e 'print "$(a)"'
100 100 14677a)

Related

Perl - Subroutine argument is another subroutine call

I have a subroutine called grepText, which simply greps a text from another variable. I am trying to split the output. Is it possible to pass the output of grepText as an argument to split directly? without putting the value of grepText in a variable first ? grepText returns a string.
What i am trying to do is:
$output = (split ":", grepText("findThis", $Alltext))[1];
grepText is as follows
sub grepText(){
my #text = split "\n", $_[1];
my $output = grep /$_[0]/, #text;
return $output;
}
it doesn't work. Error is
Too many arguments for main::grepText at a line 115, near "$Alltext)"
It is very much possible to pass the input of a subroutine to any perl function directly without using a perl variable.
I think the issue might be with your "grepText" subroutine. To debug the issue in detail, much more information is required.
I did try your routine and I was able to get the required output:
#!/usr/bin/perl
sub grepText
{
return "hello:world"; # returns a test string
}
my $output = (split ":", grepText($textToFind, $Alltext))[1];
print "$output";
Output:
world
Sure it is. But as you've written it grepText is getting some strange parameters. In
(split ":", grepText(/$textToFind/, $Alltext))[1];
you're calling grepText(/$textToFind/, $Alltext) which is searching for the value of $textToFind in the global variable $_ and, in list context, is inserting either an empty list () or a list containing 1 (1) into the parameters
So you're calling grepText($Alltext) or grepText(1, $Alltext) depending on whether $_ contains the regex pattern in $textToFind
I'm pretty certain that's not what you want to do, so some more information would be nice!
However, whatever grepText returns will be split on colons : and (split ":", grepText(...))[1] will give you the second colon-separated field, which seems to be what you're asking

Why does Perl create an empty array reference via grep?

I may be missing something obvious, but I'm at a loss as to why the following Perl creates an array reference via grep, but not sort or another general reference?
print #$arr; # no output
print ref $arr; # no output
print scalar #$arr; # no output
print ref $arr; # no output
print sort #$arr; # no output
print ref $arr; # no output
print grep { 0 } #$arr; # no output
print ref $arr; # ARRAY
I'm probably missing something obvious, or maybe it's just one of those things, but it stumped me and I wondered if anyone knew the answer...
I've tested this on Perl 5.8 and 5.10 and get the same behaviour on both.
The interesting question is why don't any of the others. Dereferencing in lvalue context will autovivify the operand if it's undef.
$ perl -E'#$arr = "b"; say $arr // "[undef]"'
ARRAY(0x335b558)
Arguments are always passed by reference to subs, so they are evaluated in lvalue context.
$ perl -E'sub f { } f( #$arr ); say $arr // "[undef]"'
ARRAY(0x284e9f8)
But the "functions" in perlfunc are actually operators, and as such, they get to invent their own syntax and calling conventions. Perl knows that sort won't modify its operands when using the default compare function, so it doesn't evaluate them in lvalue context.
$ perl -E'sort #$arr; say $arr // "[undef]"'
[undef]
grep aliases $_ to each item passed to it, so it its arguments can be modified (even though that's usually not a good idea), so its arguments are evaluated in lvalue context.
$ perl -E'#a = "a"; grep { $_ = uc($_) } #a; say #a'
A

perl, saving the command line option

I have this perl script and it takes in arguments using the getoption package.
Is there an easy way to document what was the exact command the user used to execute?
I would like to document into a log file.
Gordon
Use $0 and #ARGV together:
my $full_command = join(' ', $0, #ARGV);
or you can simply
my $full;
BEGIN { $full = "$0 #ARGV" }
#
print "log: $full\n";
form the perlvar
$LIST_SEPARATOR
$"
When an array or an array slice is
interpolated into a double-quoted
string or a similar context such as
/.../ , its elements are separated by
this value. Default is a space. For
example, this:
print "The array is: #array\n";
is equivalent to this:
print "The array is: " . join($", #array) . "\n";

How can Perl's print add a newline by default?

In Perl most of my print statements take the form
print "hello." . "\n";
Is there a nice way to avoid keeping all the pesky "\n"s lying around?
I know I could make a new function such as myprint that automatically appends \n, but it would be nice if I could override the existing print.
Raku (Perl 6) has the say function that automatically appends \n.
You can also use say in Perl 5.10 or 5.12 if you add
use feature qw(say);
to the beginning of your program. Or you can use Modern::Perl to get this and other features.
See perldoc feature for more details.
You can use the -l option in the she-bang header:
#!/usr/bin/perl -l
$text = "hello";
print $text;
print $text;
Output:
hello
hello
See "-l[octnum]" in perlrun(1) for details.
If Perl 5.10+ is not an option, here is a quick and dirty approximation. It's not exactly the same, since say has some magic when its first arg is a handle, but for printing to STDOUT:
sub say {print #_, "\n"}
say 'hello';
The way you're writing your print statement is unnecessarily verbose. There's no need to separate the newline into its own string. This is sufficient.
print "hello.\n";
This realization will probably make your coding easier in general.
In addition to using use feature "say" or use 5.10.0 or use Modern::Perl to get the built in say feature, I'm going to pimp perl5i which turns on a lot of sensible missing Perl 5 features by default.
Perhaps you want to change your output record separator to linefeed with:
local $\ = "\n";
$ perl -e 'print q{hello};print q{goodbye}' | od -c
0000000 h e l l o g o o d b y e
0000014
$ perl -e '$\ = qq{\n}; print q{hello};print q{goodbye}' | od -c
0000000 h e l l o \n g o o d b y e \n
0000016
Update: my answer speaks to capability rather than advisability. I don't regard adding "\n" at the end of lines to be a "pesky" chore, but if someone really wants to avoid them, this is one way. If I had to maintain a bit of code that uses this technique, I'd probably refactor it out pronto.
Here's what I found at https://perldoc.perl.org/perlvar.html:
$\
The output record separator for the print operator. If defined, this value is
printed after the last of print's arguments. Default is undef.
You cannot call output_record_separator() on a handle, only as a static method.
See IO::Handle.
Mnemonic: you set $\ instead of adding "\n" at the end of the print. Also, it's
just like $/ , but it's what you get "back" from Perl.
example:
$\ = "\n";
print "a newline will be appended to the end of this line automatically";
In Raku (Perl 6) there is, the say function.
If you're stuck with pre-5.10, then the solutions provided above will not fully replicate the say function. For example
sub say { print #_, "\n"; }
Will not work with invocations such as
say for #arr;
or
for (#arr) {
say;
}
... because the above function does not act on the implicit global $_ like print and the real say function.
To more closely replicate the perl 5.10+ say you want this function
sub say {
if (#_) { print #_, "\n"; }
else { print $_, "\n"; }
}
Which now acts like this
my #arr = qw( alpha beta gamma );
say #arr;
# OUTPUT
# alphabetagamma
#
say for #arr;
# OUTPUT
# alpha
# beta
# gamma
#
The say builtin in perl6 behaves a little differently. Invoking it with say #arr or #arr.say will not just concatenate the array items, but instead prints them separated with the list separator. To replicate this in perl5 you would do this
sub say {
if (#_) { print join($", #_) . "\n"; }
else { print $_ . "\n"; }
}
$" is the global list separator variable, or if you're using English.pm then is is $LIST_SEPARATOR
It will now act more like perl6, like so
say #arr;
# OUTPUT
# alpha beta gamma
#
As requested:
sub myprint { print #_, "\n"; }
myprint "foo", 3 . 'bar'
And what was the actual problem?
Maybe try understanding the language you have before trying to change it.
Man perlvar(1) says: "Within a subroutine the array #_ contains the parameters passed to that subroutine."

Why do printf and sprintf behave differently when only given an array?

sub do_printf { printf #_ }
sub do_sprintf { print sprintf #_ }
do_printf("%s\n", "ok"); # prints ok
do_sprintf("%s\n", "ok"); # prints 2
sprintf has prototype $# while printf has prototype of #
From the perldoc on sprintf:
Unlike printf, sprintf does not do
what you probably mean when you pass
it an array as your first argument.
The array is given scalar context, and
instead of using the 0th element of
the array as the format, Perl will use
the count of elements in the array as
the format, which is almost never
useful.
See codeholic's and Mark's answers for the explanation as to why they behave differently.
As a workaround, simply do:
sub do_sprintf { print sprintf(shift, #_) }
Then,
sub do_printf { printf #_ }
sub do_sprintf { print sprintf(shift, #_) }
do_printf("%s\n", "ok"); # prints ok
do_sprintf("%s\n", "ok2"); # prints ok2
They do different things. For printf the output is to a stream; for sprintf you want the string constructed. It handles the formatting (the f) of the print command. The main purpose for printf is to print out the value it constructs to a stream but with s(tring)printf(ormat) you're only trying to create the string, not print it.
printf returns the number of characters printed to a stream as feedback. Once characters are printed to a stream they've passed out of the logical structure of the program. Meanwhile, sprintf needs to hand you back a string. The most convenient way is as a return value--which because it is within the program structure can be inspected for length, or whether it contains any 'e's, or whatever you want.
Why shouldn't they behave differently?
sprintf evaluates the array in scalar context. Your array has two elements, so it evaluates as "2" (without a trailing \n).