I am writing a Perl script to generate a docker-compose.yml file. I am using the YAML.pl module's DumpFile method to write a complex hash to a file in YAML format.
Some of the arrays are dumping correctly, that is to say, the elements are unquoted, e.g.,
"environment" => [
'MYSQL_ROOT_PASSWORD=secret', 'MYSQL_DATABASE=db',
'MYSQL_USER=dbadmin', 'MYSQL_PASSWORD=secret2',
],
becomes
environment:
- MYSQL_ROOT_PASSWORD=secret
- MYSQL_DATABASE=db
- MYSQL_USER=dbadmin
- MYSQL_PASSWORD=secret2
However there are some arrays that contain what are supposed to be arguments with values comprised of environment variables that docker-compose will get from the environment, i.e., I CANNOT output the raw values here, I need to output the env var that docker-compose will use to get the value. These are being dumped quoted:
"args" => [
'APP_CODE_PATH=${APP_CODE_PATH_CONTAINER}',
'APP_GROUP=${APP_GROUP}',
'APP_GROUP_ID=${APP_GROUP_ID}',
'APP_USER=${APP_USER}',
'APP_USER_ID=${APP_USER_ID}',
'TARGET_PHP_VERSION=${PHP_VERSION}',
'TZ=${TIMEZONE}'
],
becomes:
args:
- 'APP_CODE_PATH=${APP_CODE_PATH_CONTAINER}'
- 'APP_GROUP=${APP_GROUP}'
- 'APP_GROUP_ID=${APP_GROUP_ID}'
- 'APP_USER=${APP_USER}'
- 'APP_USER_ID=${APP_USER_ID}'
- 'TARGET_PHP_VERSION=${PHP_VERSION}'
- 'TZ=${TIMEZONE}'
The output is not supposed to be quoted.
I've combed the YAML.pm docs, but I cannot find anything specific to this question there.
I suspect it is how I'm entering the values in the array, but I can't figure out what I'm doing wrong.
Use YAML::Syck instead. You can turn off that quoting, and it's off by default:
use v5.26;
use YAML::Syck;
my $hash = {
"args" => [
'APP_CODE_PATH=${APP_CODE_PATH_CONTAINER}',
'APP_GROUP=${APP_GROUP}',
],
};
print Dump($hash);
Now it's unquoted:
---
args:
- APP_CODE_PATH=${APP_CODE_PATH_CONTAINER}
- APP_GROUP=${APP_GROUP}
You could use YAML::PP instead. It tries to only quote things if really necessary, or it would look ambiguous.
YAML.pm is old, it was written for YAML 1.0, and it has a lot of bugs (as well as YAML::Syck). See matrix.yaml.io.
use YAML::PP qw(Dump);
print Dump($data);
Also, YAML::PP supports the official YAML 1.1 and 1.2 Schemas (regarding numbers, booleans etc.), while YAML.pm, YML::XS and YAML::Syck do not.
(Disclaimer: I'm the author of YAML::PP)
Regarding "The output is not supposed to be quoted": That should actually not matter. I don't think it would stop working just be cause the values are quoted. I couldn't imagine why that would be the case.
Related
First, please note that I ask this question out of curiosity, and I'm aware that using variable names like ## is probably not a good idea.
When using doubles quotes (or qq operator), scalars and arrays are interpolated :
$v = 5;
say "$v"; # prints: 5
$# = 6;
say "$#"; # prints: 6
#a = (1,2);
say "#a"; # prints: 1 2
Yet, with array names of the form #+special char like ##, #!, #,, #%, #; etc, the array isn't interpolated :
#; = (1,2);
say "#;"; # prints nothing
say #; ; # prints: 1 2
So here is my question : does anyone knows why such arrays aren't interpolated? Is it documented anywhere?
I couldn't find any information or documentation about that. There are too many articles/posts on google (or SO) about the basics of interpolation, so maybe the answer was just hidden in one of them, or at the 10th page of results..
If you wonder why I could need variable names like those :
The -n (and -p for that matter) flag adds a semicolon ; at the end of the code (I'm not sure it works on every version of perl though). So I can make this program perl -nE 'push#a,1;say"#a"}{say#a' shorter by doing instead perl -nE 'push#;,1;say"#;"}{say#', because that last ; convert say# to say#;. Well, actually I can't do that because #; isn't interpolated in double quotes. It won't be useful every day of course, but in some golfing challenges, why not!
It can be useful to obfuscate some code. (whether obfuscation is useful or not is another debate!)
Unfortunately I can't tell you why, but this restriction comes from code in toke.c that goes back to perl 5.000 (1994!). My best guess is that it's because Perl doesn't use any built-in array punctuation variables (except for #- and #+, added in 5.6 (2000)).
The code in S_scan_const only interprets # as the start of an array if the following character is
a word character (e.g. #x, #_, #1), or
a : (e.g. #::foo), or
a ' (e.g. #'foo (this is the old syntax for ::)), or
a { (e.g. #{foo}), or
a $ (e.g. #$foo), or
a + or - (the arrays #+ and #-), but not in regexes.
As you can see, the only punctuation arrays that are supported are #- and #+, and even then not inside a regex. Initially no punctuation arrays were supported; #- and #+ were special-cased in 2000. (The exception in regex patterns was added to make /[\c#-\c_]/ work; it used to interpolate #- first.)
There is a workaround: Because #{ is treated as the start of an array variable, the syntax "#{;}" works (but that doesn't help your golf code because it makes the code longer).
Perl's documentation says that the result is "not strictly predictable".
The following, from perldoc perlop (Perl 5.22.1), refers to interpolation of scalars. I presume it applies equally to arrays.
Note also that the interpolation code needs to make a decision on
where the interpolated scalar ends. For instance, whether
"a $x -> {c}" really means:
"a " . $x . " -> {c}";
or:
"a " . $x -> {c};
Most of the time, the longest possible text that does not include
spaces between components and which contains matching braces or
brackets. because the outcome may be determined by voting based on
heuristic estimators, the result is not strictly predictable.
Fortunately, it's usually correct for ambiguous cases.
Some things are just because "Larry coded it that way". Or as I used to say in class, "It works the way you think, provided you think like Larry thinks", sometimes adding "and it's my job to teach you how Larry thinks."
I have a SQL query
select name from Employee
Output :
Sharma's
How can I store this output in perl string.
I tried below :
$sql =qq {select Name from Employee};
$Arr = &DataBaseQuery( $dbHandle, $sql );
$name = $Arr;
But when I print $name I get output as
Sharma::s
How can I store the single quote in the $name.
First of all, non of standard DBI/DBD exibits behavior you listed, in my experience.
Without knowing details of what DataBaseQuery() does it's impossible to answer conclusively, but a plausible theory can be formed:
Apostrophe is a valid package separator in Perl, equivalent to "::".
Reference: perldoc perlmod
The old package delimiter was a single quote, but double colon is now the preferred delimiter, in part because it's more readable to humans, and in part because it's more readable to emacs macros. It also makes C++ programmers feel like they know what's going on--as opposed to using the single quote as separator, which was there to make Ada programmers feel like they knew what was going on. Because the old-fashioned syntax is still supported for backwards compatibility, if you try to use a string like "This is $owner's house" , you'll be accessing $owner::s ; that is, the $s variable in package owner , which is probably not what you meant. Use braces to disambiguate, as in "This is ${owner}'s house" .
perl -e 'package A::B; $A::B=1; 1;
package main;
print "double-colon: $A::B\n";
print "apostrophe: $A'"'"'B\n";'
double-colon: 1
apostrophe: 1
I have a strong suspicion something within your own libraries inside DataBaseQuery() call was written to be "smart" and to convert apostrophes to double-colons because of this.
If you can't figure out root cause, you can always do one of the following:
Write your own DB wrapper
Assuming your text isn't likely to contain "::", run a regex to fix s#::#'#g; on all results from DataBaseQuery() (likely, in a function serving as a wrapper-replacement for DataBaseQuery())
I'm using RRDs::Simple function and it needs bunch of parameters.
I have placed these parameters in a special variable (parsing, sorting and calculating data from a file) with all quotes, commas and other stuff.
Of course
RRDs::create ($variable);
doesn't work.
I've glanced through all perl special variables and have found nothing.
How to substitute name of variable for the data that contained in that variable?
At least could you tell me with what kind of tools(maybe another special variables) it can be done?
Assuming I'm understanding what you're asking:
You've build the 'create' data in $variable, and are now trying to use RRDs::create to actually do it?
First step is:
print $variable,"\n"; - to see what is actually there. You should be able to use this from the command line, with rrdtool create. (Which needs a filename, timestep, and some valid DS and RRA parameters)
usually, I'll use an array to pass into RRDs::create:
RRDs::create ( "test.rrd", "-s 300",
"DS:name:GAUGE:600:U:U", )
etc.
If $variable contains this information already, then that should be ok. The way to tell what went wrong is:
if ( RRDs::error ) { print RRDs::error,"\n"; }
It's possible that creating the file is the problem, or that your RRD definitions are invalid for some reason. rrdtool create on command line will tell you, as will RRDs::error;
I have an array of arrays that I am trying to print out (used to grab SQL database info):
my $variables_array = [[u1, answer1, Uvalue], ["v1", u2, v2, answer2, Vvalue]];
When I print out $variables_array all of the variables except for v2 are printed out with the formatting I have above. I searched google/SO and could not find any special significance for v# in Perl. I noticed that notepad++ changes the color of v# in the array of arrays indicating it is some kind of special variable, but I cannot tell what it is? Can someone please shed some light on this for me, I'm confused.
Perl has a lot of different literals
Numbers like 123, 123.0, 1.23e2, 0x7b
String literals "abc", 'abc', q/abc/, …
Barewords
Barewords look like function calls without a param list
In special places, this is OK even under strict: Foo::Bar->new()
without strict 'refs', barewords that don't signify subs are treated as strings.
the LHS of the fat comma => is always autoquoted
Barewords with leading minus are always strings, unless they are file-test operators. -abc eq "-abc"
V-strings (V as in vector, or version). v1.2.3
V-strings consist of a sequence of numbers that are seperated by a period. Each of the numbers is translated to a corresponding character. As they are strings, they can be compared with lt, gt, etc.
They are good for e.g. IP addresses, or version numbers. They are not good for being printed out, as low numbers signify unprintable characters.
$ perl -E'say v49.50.51'
123
The moral of the story? Always use strict; use warnings;, and maybe look into the qw// quoting operator:
my $variables_array = [[qw/u1 answer1 Uvalue/], [qw/v1 u2 v2 answer2 Vvalue/]];
# or verbose:
my $variables_array = [['u1', 'answer1', 'Uvalue'], ['v1', 'u2', 'v2', 'answer2', 'Vvalue']];
(qw does not interpolate, splits the string at any whitespace, and is equal to the list of strings)
With no strict or warnings, I get:
$variables_array: [
[
'u1',
'answer1',
'Uvalue'
],
[
'v1',
'u2',
v2,
'answer2',
'Vvalue'
]
]
amon's answer explains that they are "barewords". Barewords are deprecated in almost all contexts (perhaps not command-line scripts, though).
Notice that it quotes 'v1' but not 'v2', that because a version string--a number beginning with a v--are legal literals in Perl.
I have searched around the Internet and the Perl doc and can't seem to find the answer.
Help will be appreciated.
EDIT:: He asked me about -G, wrote it down on a piece of paper and when i looked stumped asked me to go read up on the basics.
I agree with JesperE, please show us some code. However, as far as I can tell, this is what's happening:
if(-G) {
Perl sees this, doesn't recognize -G, and so treats it as a string. It becomes:
if('-G') {
Which is equivalent to:
if(1) {
So as far as I can tell, if(-G) does nothing. I've tried using it, and it always seems to return true, which supports my hypothesis. Further support is from the following code (tested on OS X with Perl 5.10.0):
use strict;
use warnings;
my $var = -G;
print "$var\n";
Displays no warnings, compiles and runs, and prints simply "-G".
EDIT: Doing a search I should have done much earlier provides the following from Perldoc's perlop page:
Unary "-" performs arithmetic negation if the operand is numeric. If the operand is an identifier, a string consisting of a minus sign concatenated with the identifier is returned. Otherwise, if the string starts with a plus or minus, a string starting with the opposite sign is returned. One effect of these rules is that -bareword is equivalent to the string "-bareword". If, however, the string begins with a non-alphabetic character (excluding "+" or "-"), Perl will attempt to convert the string to a numeric and the arithmetic negation is performed. If the string cannot be cleanly converted to a numeric, Perl will give the warning Argument "the string" isn't numeric in negation (-) at ....
As stated in the comments, B::Deparse appears to show that Perl converts if(-G) to if(-'G'). However, the documentation (and the behavior with print()) are consistent with the documentation, which says that it should convert if(-G) to if('-G'). This doesn't change the result of the program either way.
However, subtle typing differences in the behaviors of unary operators that 99% of people will only ever use on numbers are not what I would call "basic." I don't think anyone should (or would ever need to) use the -bareword to 'bareword' conversion in any practical situation.
There's no switch -G in perl.
perl -G
Unrecognized switch: -G (-h will show valid options).
Edit: OK, there's nothing with -G either - only -g.
-g File has setgid bit set.
http://perldoc.perl.org/perlfunc.html
Otherwise, it's nonsense and the question is misphrased.
I don't know about -G but -g is described here as
-g File has setgid bit set.
This is clearly confusion between [ (test) options and Perl -X file tests. -G is in the former (on my BSD system), but not the latter. -G is a non-posix extension and I guess Perl didn't include all the extensions, just some. So its either, he meant to say -g or he meant [ -G $file ]; (for some superset of POSIX [). It is also in my default shell (pdksh) and bash (the linux default shell, for the most part)
-G in test or as a shell builtin here:
-G file
True if file exists and its group matches the effective group ID
of this process.
One answer says: "I don't think anyone should (or would ever need to) use the -bareword to -'bareword' conversion in any practical situation."
This is widely used in one style of named parameters. See the venerable CGI for one:
$cookie1 = $q->cookie(-name=>'riddle_name', -value=>"The Sphynx's Question");
$cookie2 = $q->cookie(-name=>'answers', -value=>\%answers);
print $q->header(
-type => 'image/gif',
-expires => '+3d',
-cookie => [$cookie1,$cookie2]
);