Using hexadecimal values in a Perl variable - perl

I have a variable, $count, which will take a decimal value from the command line, and I have a piece of code which generates files with name filename001 filename002 ....filename00a,filename00b etc. It appends a hexadecimal number(without 0x) to filename for every new file it generates.
I use the variable $count to keep track of the number that is appended to filename. I want to pull out lines containing a particular text Result: from the generated file (filename00b filename00a, etc.). For this purpose I use the grep tool in the following way:
`grep "Result:" path to the file/filename0*$count`
This works fine till I reach the 10th file when 10 becomes a in hexadecimal, but $count in the grep command is simplified to 10, so grep is not able to find the file. I tried using hex($count), but it does not seem to work. It required that $count variable can be incremented or decremented, and it still holds the hex value. Is there a way to do this?

The hex function in perl interprets its argument as a hex string and returns the corresponding integer value, for example:
print hex '0xAf'; # prints '175'
print hex 'aF'; # same
This from the definition of hex in perldoc -f hex.
It seem you want to do the opposite, convert your decimal number to a hex representation. You can do that with printf for example:
printf("%03x", 175); # prints '0af'
printf("%03x", 0xAf); # same
If you want to save the value in a variable, use sprintf instead of printf, it returns the string instead of printing it.

Related

I have two problems converting data using Perl?

I want to convert this input {111,222},{333,444},{555,666} so that the output be like this 111;222;333;444;555;666. The same thing goes for {111,222},{333,444} to 111;222;333;444 and {111,222} to 111;222.
I want to convert this date format from 2019-11-12 15:25:19 to 11/12/2019 15:25:19 and 2019-11-04T15:26:11.000+00:00 to 11/12/2019 15:25:19.
You could use a simple script like this:
#!/usr/bin/perl -pl
s/^\{//;
s/\}$//;
s/\}?,\{?/;/g;
The shebang line says read input lines and print the modified form of each one (-p) and handle line endings automatically (-l).
The first s/// removes a leading {. The second removes a trailing }. The last replaces },{ and , with ; across the line.
You could use a simple script like this (assuming that you really want 2019-11-04T15:26:11.000+00:00 mapped to 11/04/2019 15:26:11 and not the other value which is 8 days bar 52 seconds after the input value):
#!/usr/bin/perl -pl
s%(\d{4})-(\d\d)-(\d\d)[T ](\d\d:\d\d:\d\d).*%$2/$3/$1 $4%;
The shebang line is the same as before. The regex looks for 4 digits, dash, 2 digits, dash, 2 digits, blank or T, an hh:mm:ss string and stray junk and reformats it in the correct sequence.
Between them, they produce the desired results.
Of course, this being Perl, TMTOWTDI — timtoady, or "there's more than one way to do it":
$ cat data
{111,222},{333,444},{555,666}
{111,222},{333,444}
{111,222}
$ cat data.2
2019-11-12 15:25:19
2019-11-04T15:26:11.000+00:00
$ perl -pl -e 's/^\{//; s/\}$//; s/\}?,\{?/;/g; s%(\d{4})-(\d\d)-(\d\d)[T ](\d\d:\d\d:\d\d).*%$2/$3/$1 $4%;' data data.2
111;222;333;444;555;666
111;222;333;444
111;222
11/12/2019 15:25:19
11/04/2019 15:26:11
$
Just transliterating sequences of non-digits to ;:
$data =~ y/0-9/;/cs;

Cannot get correct return value in sprintf function call

My problem is that the return value im printing is not being translated into a value.
I have the following code in a test file.
#!/usr/bin/perl -I/srv/www/jonathan/m/www
my $var = sprintf("$%.1f lbs",(77*2.20462));
print $var;
Its returning: 0.1f instead of the value i need to see.
What am i doing incorrectly here? I'm a perl newbie.
Your problem is that Perl interprets "$%.1f" as the variable $% followed by ".1f". $% is a special Perl variable containing "The current page number of the currently selected output channel" (see perlvar) and that has the value 0, so what gets printed is the string "0.1f".
There are a few ways round this.
You can remove the dollar sign: sprintf("%.1f lbs",(77*2.20462)). But that changes the string that you display.
You can escape the dollar to tell Perl that it's not special: sprintf("\$%.1f lbs",(77*2.20462)).
But I think there's a better solution. Perl treats dollar signs as special characters in double-quoted strings. But there's no reason for your string to be double-quoted. So just change your format string to use single quotes: sprintf('$%.1f lbs',(77*2.20462)).
That last one is the solution I'd use.
Perl uses dolar($) symbol to declare a scalar variable, you need to remove the $ symbol from the sprintf.
corrected code
my $var = sprintf("%.1f lbs",(77*2.20462));
print $var;
output
169.8 lbs

What does \x do in print

I would like to start by saying that I am not familiar with Perl. That being said, I came across this piece of code and I could not figure out what the \x was for in the code below. In addition, I was unsure why nothing was displayed when I ran the following:
perl -e 'print "\x7c\x8e\x04\x08"'
It's not about print: it's about string representation, in which codes represent characters from your character set. For more information you should read Quote and Quote-like Operators and Effects of Character Semantics
In your case the character code is in hex. You should look in your character set table, and you may need to convert to decimal first.
You said "I was unsure why nothing was displayed when I ran the following:"
perl -e 'print "\x7c\x8e\x04\x08"'
That command outputs 4 characters to STDOUT. Each of the characters is specified in hexadecimal. The "\x7c" part will output the vertical bar character |. The other three characters are control characters, so probably wouldn't produce any visible output. If you redirect output to a file, you will end up with a 4 byte file.
It's possible that you're not seeing the vertical bar character because it's being overwritten by your command prompt. Unlike the shell echo or Python's print, Perl's print function does not automatically append a newline to all output. If you want new lines, you can insert them in the string using \n.
\x signifies the start of a hexadecimal character notation.

Perl - Detect from command line if file has only a specified character

This was the original question.
Using perl, how can I detect from the command line if a specified file contains only a specified character(s), like '0' for example?
I tried
perl -ne 'print if s/(^0*$)/yes/' filename
But it cannot detect all conditions, for example multiple lines, non-zero lines.
Sample input -
A file containing only zeros -
0000000000000000000000000000000000000000000000000000000000000
output - "yes"
Empty file
output - "no"
File containing zeros but has newline
000000000000000000
000000000000
output - "no"
File containing mixture
0324234-234-324000324200000
output - "no"
-0777 causes $/ to be set to undef, causing the whole file to be read when you read a line, so
perl -0777ne'print /^0+$/ ? "yes" : "no"' file
or
perl -0777nE'say /^0+$/ ? "yes" : "no"' file # 5.10+
Use \z instead of $ if want to make sure there's no trailing newline. (A text file should have a trailing newline.)
To print yes if a file contains at least one 0 character and nothing else, and otherwise no, write
perl -0777 -ne 'print /\A0+\z/ ? "yes" : "no"' myfile
I suspect you want a more generic solution than just detecting zeroes, but I haven't got time to write it for you till tomorrow. Anyway, here is what I think you need to do:
1. Slurp your entire file into a single string "s" and get its length (call it "L")
2. Get the first character of the string, using substr(s,0,1)
3. Create a second string that repeats the first character "L" times, using firstchar x L
4. Check the second string is equal to the slurped file
5. Print "No" if not equal else print "Yes"
If your file is big and you don't want to hold two copies in memory, just test character by character using substr(). If you want to ignore newlines and carriage returns, just use "tr" to delete them from "s" before step 2.

In Perl, why does variable interpolation fail for a hexadecimal escape sequence?

In Perl, if I run the code:
print "Literal Hex: \x{50} \n";
I get this: "Literal Hex: P"
However, if I run the code:
my $hex_num = 50;
print "Interpolated Hex: \x{$hex_num}";
The variable does not interpolate properly and I get this: "Interpolated Hex:"
Similar failure results when I attempt to use variable interpolation in unicode and octal escape sequences.
Is it possible to use escape sequences (e.g. \x, \N) with interpolated string variables? I was under the impression that a $variable contained within double quotes is always interpolated, but is this the exception?
Note: Thanks to this question, I am aware of the workaround: chr(hex($hex_num)), but my above questions regarding variable interpolation for escape sequences still stand.
Interpolation is not recursive, everything is interpolated just once, from left to right. Therefore, when \x{$hex} is being processed, the following applies (cited from perlop):
If there are no valid digits between the braces, the generated character is the NULL
character ("\x{00}").
Zero is really there:
perl -MO=Deparse -e '$h=50;print "<\x{$h}>"'
$h = 50;
print "<\000>";
-e syntax OK
You should put in your variable the complete scape sequence:
my $hex_num = "\x50";
print "Interpolated Hex: $hex_num", "\n";
The issue I had was adding an escaped var into another variable such as:
$MYVAR = "20";
$myQuery = "\x02\x12\x10\x$MYVAR\x10";
Tried a number of \\x, \Q\x and various other escape sequences to no avail!!!
My workaround was not a direct escape but converting the var prior to adding to the string.
$MYVAR = chr(hex(20));
Did quite a bit of searching for a direct regex solution but had to run with this in the end.