I have a string whose middle part will be changed based on a condition.
Something like this:
"You have x number of problems";
The value of x has different text based on some if conditions.
One way I could do is to store "You have" in one variable and "number of problems" in another variable and
do something like sprintf("%s%d%s", $firstpart, $x, $secondpart);
Is there a better way to do this?
Generally, strings are constructed in Perl using interpolation: put the variable right in the string.
my $numProblems = 99;
my $text = "You got $numProblems problems, but Perl ain't one.";
This only works on simple variables, and things like array and hash access. Expressions and method calls don't work.
# Accessing a hash or array works.
my $text = "You got $numProblems{$user} problems, but Perl ain't one.";
# Method call does not work.
my $text = "You got $user->numProblems problems, but Perl ain't one.";
You can use the baby-cart "secret operator" to fool Perl into interpolating expressions.
my $text = "You got #{[$user->numProblems]} problems, but Perl ain't one.";
You can read about all the Gory Details Of Interpolation in perlop.
You can also use sprintf, but generally that's only when you need to do formatting. There's no need for separate variables for the start and end of the string.
my $text = sprintf "You got %d problems, but Perl ain't one.", $numProblems;
Related
I am unable to pass values like 750_000 from command line to a function like usleep via shift. Still getting ".. isn't numeric".
Any ideas?
Thanks.
The 750_000 syntax is valid for numeric literals in source code, where it is simply ignored when populating the value. It is not valid when using a string that's already been created (such as read from commandline arguments) as a number. Numbers can be stored in strings with scientific notation as you noted. Alternatively you could remove the underscores yourself:
use strict;
use warnings;
use Time::HiRes 'usleep';
my $num = shift;
$num =~ tr/_//d;
usleep $num;
Sorry but answering my own question.
It can be done using exponent syntax.
examples:
1_000_000 can be written as 1e6
1_234_567 can be written as
1.234567e6
for my $item (#array) {
if (index($item, '$n') != -1) {
print "HELLO\n";
}
}
Problem is: Perl critic gives below policy violation.
String may require interpolation at line 168, near '$item, '$n''. (Severity: 1)
Please advise how do I fix this?
In this case the analyzer either found a bug or is plain wrong in flagging your code.
Are you looking for a literal "$n" in $item, or for what $n variable evaluates to?
If you want to find the literal $n characters then there is nothing wrong with your code
If you expect $item to contain the value stored in $n variable then allow it to be evaluated,
if (index($item, $n) != -1)
If this is indeed the case but $n may also contain yet other escaped sequences or encodings which you need as literal characters (so to suppress their evaluation) then you may need to do a bit more, depending of what exactly may be in that variable.
In case you do need to find characters $ followed by n (what would explain a deliberate act of putting single quotes around a variable) you need to handle the warning.
For the particular policy that is violated see Perl::Critic::Policy::ValuesAndExpressions
This policy warns you if you use single-quotes or q// with a string that has unescaped metacharacters that may need interpolation.
To satisfy the policy you'd need to use double quotes and escape the $, for example qq(\$n). In my opinion this would change the fine original code segment into something strange to look at.
If you end up wanting to simply silence the warning see documentation, in Bending The Rules
A comment. The tool perlcritic is useful but you have to use it right. It's a static code analyzer and it doesn't know what your program is doing, so to say; it can catch bad practices but can't tell you how to write programs. Many of its "policies" are unsuitable for particular code.
The book that it is based on says all this very nicely in its introduction. Use sensibly.
When I look at the question where this comes from it appears that you are looking for index at which substrings were matched, so you need the content of $n variable, not literal "$n". Then perlcritic identified a bug in the code, good return for using it!
I am fairly new to unix bash scripting and need to know if this is possible. I want to ask user for their input multiple times and then store that input in to one variable.
userinputs= #nothing at the start
read string
<code to add $string to $userinputs>
read string
<code to add $string to $userinputs> #this should add this input along with the other input
so if the user enters "abc" when asked first time, it add's "abc" in $userinputs
then when asked again for the input and the user enters "123" the script should store it in the same $userinputs
this would make the $userinput=abc123
The usual way to concat two strings in Bash is:
new_string="$string1$string2"
{} are needed around the variable name only if we have a literal string that can obstruct the variable expansion:
new_string="${string1}literal$string2"
rather than
new_string="$string1literal$string2"
You can also use the += operator:
userinputs=
read string
userinputs+="$string"
read string
userinputs+="$string"
Double quoting $string is optional in this case.
See also:
How to concatenate string variables in Bash?
You can concatentate variables and store multiple strings in the same one like so:
foo=abc
echo $foo # prints 'abc'
bar=123
foo="${foo}${bar}"
echo $foo # prints 'abc123'
You can use the other variables, or the same variable, when assigning to a variable, e.g. a="${a}123${b}". See this question for more info.
You don't have to quote the strings you're assigning to, or do the ${var} syntax, but learning when to quote and not to quote is a surprisingly nuanced art, so it's often better to be safe than sorry, and the "${var}" syntax in double quotes is usually the safest approach (see any of these links for more than you ever wanted to know: 1 2 3).
Anyway, you should read into a temporary variable (read, by default, reads into $REPLY) and concatentate that onto your main variable, like so:
allinput=
read # captures user input into $REPLY
allinput="${REPLY}"
read
allinput="${allinput}${REPLY}"
Beware that the read command behaves very differently depending on supplied switches and the value of the IFS global variable, especially in the face of unusual input with special characters. A common "just do what I mean" choice is to empty out IFS via IFS= and use read -r to capture input. See the read builtin documentation for more info.
When looking at examples of variable substitution in GStrings, I have noticed two difference syntaxes. This can be seen here: Groovy Templates
This has the example:
def text = 'Dear "$firstname $lastname",\nSo nice to meet you in <% print city %>.\nSee you in ${month},\n${signed}'
It looks like ${variable} is used more commonly when you have an expression, but $variable is used when you just have a single variable, but even here they mix it with $firstname and ${month}. Is there a reason to do it one way or another when you have a single variable and not an expression, or does it not matter?
It doesn't matter...
As you say, if you have an expression like "${name.toUpperCase()}", "${number}th" or "${list[0]}", then it has to be inside braces, but both "${name}" and "$name" are the same.
Indeed, so long as it's simple property access you can omit the braces, ie: "Hello $person.username"
It could be said that adding the braces can make your string templates easier to read, but that's a personal preference thing.
I'm not sure how to do this but I figured I would ask here.. I'm trying to create a string of specific environment variables such that:
$A = "foo"
$B = "bar"
$C = "baz"
would give "foo, bar, baz"
Unfortunately, it doesn't seem that the Bourne shell supports arrays, which would have made these easily solvable. The other way I'm trying to solve this is by directly inserting my own variable called $COMMA after each environment variable, however I am getting syntax errors so I'm not sure how to do this correctly. Would appreciate any advice here, thanks!
Your variables shouldn't start with $ unless you want the value of them (this isn't perl or php...)
A=foo
B=bar
C=baz
echo $A,$B,$C
or even:
A=foo B=bar C=baz echo $A,$B,$C
will give you a comma seperated list of the variables you defined.