Perl -e field substitution - perl

I am using perl -e to convert a hexadecimal number(523cc261) to a meaningful date:
perl -e 'my $t=localtime 0x523cc261; print $t . "\n"'
Fri Sep 20 21:47:13 2013
However i am not able to script it as above code needs the value to be provided on prompt.I tried substituting 523cc261 with a variable but it does not work:
b=523cc261
perl -e 'my $t=localtime 0x`echo b`; print $t . "\n"`
Backticks found where operator expected at -e line 1, near "0x`echo b`"
(Missing operator before `echo b`?)
syntax error at -e line 1, near "0x`echo b`"
My question is how to provide the decimal value(523cc261) via argument in a script.

Easiest way will be to pass the time to the Perl script as an argument. I've rewritten the script to be a little more concise, too:
% b=523cc261
% perl -E 'say scalar localtime hex $ARGV[0]' $b
Fri Sep 20 14:47:13 2013

You can use the ENV HASH :
$ b=523cc261 perl -le 'my $t = scalar localtime hex $ENV{"b"}; print $t;'
Another solution (a bit obfuscated, $b is a shell variable) :
$ b=523cc261 perl -le 'my $t = scalar localtime hex "'$b'"; print $t;'

Related

perl - How to print utf8 code points for each byte

I'm trying to print the code points for all possible byte values.
My test file :
$ perl -e ' open($fh,">raw_bytes.dat");while($i++<256){ print $fh chr($i-1) } close($fh)'
$ ls -l raw_bytes.dat
-rw-rw-r--+ 1 uuuuu Domain Users 256 Mar 20 15:41 raw_bytes.dat
$
What should go into the below #---> part so that I print the code points of utf8 $x in hexadecimal?
perl -e ' use utf8; open($fh,"<raw_bytes.dat");binmode($fh);
while($rb=read($fh,$x,1)) { utf8::encode($x);
#--->
} '
I tried %02x using printf, but it didn't work. Also, I want the solution only using core modules.
Use unpack('H*'):
$ perl -e '$x="\x80"; utf8::encode($x); print unpack("H*", $x), "\n"'
c280
For your example file I get
$ perl -e 'open($fh, "<", "raw_bytes.dat"); binmode($fh);
while ($rb=read($fh,$x,1)) { utf8::encode($x);
print unpack("H*", $x), "\n";
}'
00
01
02
03
...
7f
c280
c281
c282
c283
...
c3bd
c3be
c3bf
Variants:
$ perl -e '$x="\x80"; utf8::encode($x);
print uc(unpack("H*", $x)), "\n"'
C280
$ perl -e '$x="\x80"; utf8::encode($x);
($r = uc(unpack("H*", $x))) =~ s/(..)/\\X\1/g;
print "$r\n"'
\XC2\X80
# a little bit pointless example, but assume that $x is a provided Perl scalar....
$ perl -e '$x="\N{U+0080}\N{U+0081}";
printf("U+%04x ", ord($_)) foreach(split(//, $x));
print "\n";'
U+0080 U+0081
Please remember the difference between
a scalar holding a raw string: split(//) returns octets, e.g. \x80
a scalar holding a properly encoded string: split(//) returns characters, e.g. \N{U+0080}
I tried %02x using printf, but it didn't work.
You can use
printf "%vX\n", $x;
According to perldoc sprintf:
vector flag
This flag tells Perl to interpret the supplied string as a vector of
integers, one for each character in the string. Perl applies the
format to each integer in turn, then joins the resulting strings with
a separator (a dot . by default). This can be useful for displaying
ordinal values of characters in arbitrary strings.

Is it possible get a particular argument in printf format in perl in command line?

It's needed to build a string foobar is not foo and not bar.
In printf format %$2s, "2" means a particular argument position.
But it doesn't work in perl:
$ perl -e "printf('%$1s$2s is not %$1s and not %$2s', 'foo', 'bar');"
%2 is not %1 and not %2
My env:
$ perl --version
This is perl 5, version 16, subversion 3 (v5.16.3) built for x86_64-linux-thread-multi
(with 29 registered patches, see perl -V for more detail)
Your quoting is off.
perl -E 'say sprintf(q{%1$s%2$s is not %1$s and not %2$s}, "foo", "bar");'
foobar is not foo and not bar
You cannot use double quotes "" for the -e because your shell gets confused. You need single quotes there. But if you use double quotes for the printf pattern with the %1$s syntax, Perl will try to interpolate the $s, which doesn't work. So use a non-quoting q{} or escape the single quotes '' with \'. Or escape the $s.
If you turn on use strict and use warnings you'll see:
$ perl -E 'use strict; use warnings; say sprintf("%1$s%2$s is not %1$s and not %2$s", "foo", "bar");'
Global symbol "$s" requires explicit package name at -e line 1.
Global symbol "$s" requires explicit package name at -e line 1.
Global symbol "$s" requires explicit package name at -e line 1.
Global symbol "$s" requires explicit package name at -e line 1.
Execution of -e aborted due to compilation errors.
That's with single quotes '' for -e and double quotes "" for the pattern.
$ perl -E "use strict; use warnings; say sprintf('%1$s%2$s is not %1$s and not %2$s', 'foo', 'bar');"
Invalid conversion in sprintf: "%1 " at -e line 1.
Invalid conversion in sprintf: "%2" at -e line 1.
%2 is not %1 and not %2
Now the shell tried to interpolate $s because of the double quotes "". So Perl never sees it. It sees the pattern as "%1 %2 is not %1 and not %2", which it cannot understand. (Note that the % will not get interpolated in double quoted strings in Perl).
This works for me on *nix:
perl -e "printf('%s%s is not %1\$s and not %2\$s', 'foo', 'bar');"
See the sprintf documentation, in particular the examples at the very end:
Here are some more examples; be aware that when using an explicit index, the $ may need escaping:
printf "%2\$d %d\n", 12, 34; # will print "34 12\n"
printf "%2\$d %d %d\n", 12, 34; # will print "34 12 34\n"
printf "%3\$d %d %d\n", 12, 34, 56; # will print "56 12 34\n"
printf "%2\$*3\$d %d\n", 12, 34, 3; # will print " 34 12\n"
printf "%*1\$.*f\n", 4, 5, 10; # will print "5.0000\n"
Let's have a look at the program you pass to perl:
$ printf '%s' "printf('%$1s$2s is not %$1s and not %$2s', 'foo', 'bar');"
printf('%ss is not %s and not %s', 'foo', 'bar');
As you can see, there is no $1 or $2 in your program because you improperly built your shell command. Just like Perl interpolates in double-quotes, so do sh and related shells. You should be using single quotes!
perl -e'printf("%\$1s\$2s is not %\$1s and not %\$2s\n", "foo", "bar");'
(I would have suggested switching from '' to q{} inside the Perl program so you wouldn't have to escape the dollar signs, but you need double-quotes for the \n you were missing anyway.)

perl -n with input from pipe and #ARGV

I've got a one-liner like this:
date +%H | perl -ne 'printf "%02d", $_ - ($ARGV[0] - 1);' 1
It says:
Can't open 1: Datei oder Verzeichnis nicht gefunden.
The error message means "File or directory not found".
I want it to take both the output from date and the commandline argument at the same time.
Essentially it should get me the current hour minus the argument minus one. If there are better ways to achieve this, I'll happily accept them. I'd still be grateful about an explanation as to why this doesn't work.
Let's assume it's after 10am now.
Param Output
1 10
2 09
3 08
The result might be yesterday or even further back in the past, it does not make much sense to print just the hour.
perl -mDateTime -e'
my $dt = DateTime->now;
$dt->subtract(hours => 1);
$dt->subtract(hours => shift #ARGV);
print $dt->hour;
' 4
Whereever possible, use a standard datetimestamp, such as RFC3339 which is in wide use.
perl -mDateTime -mDateTime::Format::RFC3339 -e'
my $dt = DateTime->now;
$dt->subtract(hours => 1);
$dt->subtract(hours => shift #ARGV);
print DateTime::Format::RFC3339->new->format_datetime($dt);
' 4
Your Perl one-liner deparses to:
LINE: while (defined($_ = <ARGV>)) {
printf '%02d', $_ - ($ARGV[0] - 1);
}
… because of -n. ARGV:
The special filehandle that iterates over command-line filenames in #ARGV.
But you have no filenames as arguments.
perl -n creates an implicit loop reading files listed as arguments or STDIN if there are no arguments; this conflicts with your use of an argument for something different. You can fix it by clearing #ARGV in a BEGIN block:
date +%H | perl -ne 'BEGIN{ $arg=shift } printf "%02d", $_ - ($arg - 1);' 1
but for this particular task, you're better off doing the date calculation entirely in perl anyway.

Perl print formatting

I would like to format(truncate/append with chars) a string to a specified length while printing in Perl.
For example
$string='my_string';
printf("%04s",$string);
should print
my_s
also if
$string='my';
I should get
00my
Is there any way to print last four characters ?
ring
and if string is
$string='my';
it should print
00my
You want to do this format string instead of yours:
printf ("%04.4s", $string);
You need the .4 because this specifies maximum length. (The 4 at the beginning specifies a minimum only)
here are the output of some tests:
$ perl -e "my \$string = \"my_string\";print sprintf(\"%04.4s\", 22);"
0022
$ perl -e "my \$string = \"my_string\";print sprintf(\"%04.4s\", \$string);"
my_s
$ perl -e "my \$string = \"my\";print sprintf(\"%04s\", \$string);"
00my
Here is the output using the wrong format string. As you can see strings are not truncated.
$ perl -e "my \$string = \"my_string\";print sprintf(\"%04s\", 22);"
0022
$ perl -e "my \$string = \"my_string\";print sprintf(\"%04s\", \$string);"
my_string
printf('%04s', substr($_, 0, 4));

Why does defined sdf return true in this Perl example?

I tried this example in Perl. Can someone explain why is it true?
if (defined sdf) { print "true"; }
It prints true.
sdf could be any name.
In addition, if there is sdf function defined and it returns 0, then it does not print anything.
print (sdf); does not print sdf string but
if (sdf eq "sdf")
{
print "true";
}
prints true.
The related question remains if sdf is a string. What is it not printed by print?
sdf is a bareword.
perl -Mstrict -e "print qq{defined\n} if defined sdf"
Bareword "sdf" not allowed while "strict subs" in use at -e line 1.
Execution of -e aborted due to compilation errors.
For more fun, try
perl -Mstrict -e "print sdf => qq{\n}"
See Strictly speaking about use strict:
The subs aspect of use strict disables the interpretation of ``bare words'' as text strings. By default, a Perl identifier (a sequence of letters, digits, and underscores, not starting with a digit unless it is completely numeric) that is not otherwise a built-in keyword or previously seen subroutine definition is treated as a quoted text string:
#daynames = (sun, mon, tue, wed, thu, fri, sat);
However, this is considered to be a dangerous practice, because obscure bugs may result:
#monthnames = (jan, feb, mar, apr, may, jun,
jul, aug, sep, oct, nov, dec);
Can you spot the bug? Yes, the 10th entry is not the string 'oct', but rather an invocation of the built-in oct() function, returning the numeric equivalent of the default $_ treated as an octal number.
Corrected: (thanks #ysth)
E:\Home> perl -we "print sdf"
Unquoted string "sdf" may clash with future reserved word at -e line 1.
Name "main::sdf" used only once: possible typo at -e line 1.
print() on unopened filehandle sdf at -e line 1.
If a bareword is supplied to print in the indirect object slot, it is taken as a filehandle to print to. Since no other arguments are supplied, print defaults to printing $_ to filehandle sdf. Since sdf has not been opened, it fails. If you run this without warnings, you do not see any output. Note also:
E:\Home> perl -MO=Deparse -e "print sdf"
print sdf $_;
as confirmation of this observation. Note also:
E:\Home> perl -e "print asdfg, sadjkfsh"
No comma allowed after filehandle at -e line 1.
E:\Home> perl -e "print asdfg => sadjkfsh"
asdfgsadjkfsh
The latter prints both strings because => automatically quotes strings on the LHS if they consist solely of 'word' characters, removing the filehandle interpretation of the first argument.
All of these examples show that using barewords leads to many surprises. You should use strict to avoid such cases.
This is a "bareword". If it is allowed, it has the value of "sdf", and is therefore not undefined.
The example isn't special:
telemachus ~ $ perl -e 'if (defined sdf) { print "True\n" };'
True
telemachus ~ $ perl -e 'if (defined abc) { print "True\n" };'
True
telemachus ~ $ perl -e 'if (defined ccc) { print "True\n" };'
True
telemachus ~ $ perl -e 'if (defined 8) { print "True\n" };'
True
None of those is equivalent to undef which is what defined checks for.
You might want to check out this article on truth in Perl: What is Truth?
defined returns true if the expression has a value other than the undefined value.
the defined function returns true unless the value passed in the argument is undefined. This is useful from distinguishing a variable containing 0 or "" from a variable that just winked into existence.