In Python, if I do this:
print "4" * 4
I get
> "4444"
In Perl, I'd get
> 16
Is there an easy way to do the former in Perl?
$ perl -e 'print "4" x 4; print "\n"'
4444
The x operator is documented in perldoc perlop. Here binary means an operator taking two arguments, not composed of bits, by the way.
Binary "x" is the repetition operator. In scalar context or if the
left operand is not enclosed in parentheses, it returns a string consisting
of the left operand repeated the number of times specified by the right
operand. In list context, if the left operand is enclosed in parentheses
or is a list formed by "qw/STRING/", it repeats the list. If the right
operand is zero or negative, it returns an empty string or an empty
list, depending on the context.
print '-' x 80; # Print row of dashes
print "\t" x ($tab/8), ' ' x ($tab%8); # Tab over
#ones = (1) x 80; # A list of 80 1’s
#ones = (5) x #ones; # Set all elements to 5
perl -e is meant to execute Perl code from the command line:
$ perl --help
Usage: perl [switches] [--] [programfile] [arguments]
-e program one line of program (several -e's allowed, omit programfile)
In Perl, you want to use the "x" operator.
Note the difference between
"4" x 4
and
("4") x 4
The former produces a repeated string:
"4444"
the latter a repeated list:
("4", "4", "4", "4")
It's very similar in Perl
print "4" x 4;
FWIW, it’s also print 4 x 4 in Perl.
In general, in Perl, operators are monomorphic, ie. you have different sets of operators for string semantics, for numeric semantics, for bitwise semantics, etc., where it makes sense, and the type of the operands largely doesn’t matter. When you apply a numeric operator to a string, the string is converted to a number first and you get the operation you asked for (eg. multiplication), and when you apply a string operator to a number, it’s turned into a string and you get the operation you asked for (eg. repetition). Perl pays attention to the operator first and the types of the operands only second – if indeed it pays them any mind at all.
This is the opposite of Python and most other languages, where you use one set of operators, and the types of the operands determine which semantics you’ll actually get – ie. operators are polymorphic.
If you want to print 10 character "A"s, you can also do this
perl -e 'print "A" x 10'; echo
Example with output
user#linux:~$ perl -e 'print "A" x 10'; echo
AAAAAAAAAA
user#linux:~$
All answers, given so far, missed mentioning that the operator x does not only work on string literals, but also on variables that are strings or expressions that evaluate to strings like
use feature 'say';
my $msg = "hello ";
say $msg x 2;
say chr(33) x 3;
like this
hello hello
!!!
and, even more important, x does an automatic conversion of expressions into strings if they aren't already (thanks to ggorlen for pointing me into that direction!). So for example
say 4 x 2;
say [$msg] x 2;
will result in something like the following as output
44
ARRAY(0x30ca10)ARRAY(0x30ca10)
Came this way looking for an answer. Didn't quite find what I was looking for so I thought I'd share my learning. I wanted to compose dynamic SQL CRUD statements with the appropriate number of placeholders.
$table = "ORDERS";
#fields = ("ORDER_ID", "SALESMAN_ID", "CUSTOMER_ID", "ORDER_DATE", "STATUS");
$sql = "INSERT INTO $table (" . join(',', #fields) . ') VALUES (' . '?,' x (#fields - 1) . '?)';
print $sql;
The output looks like this...
INSERT INTO ORDERS (ORDER_ID,SALESMAN_ID,CUSTOMER_ID,ORDER_DATE,STATUS) VALUES (?,?,?,?,?)
Related
I have one doubt I have started learning Linux and learn about the way we can perform mathematical operations. for example
a) using expr > $ and space are mandatory.
example: sum= expr $a + $b
b) using let keyword > $ is optional but we should use space.
c) using (()) > both $ and space is optional.
d) using [ ] > both $ and space is optional.
so now I have written one simple if statement.
#! /bin/bash
read -p "Please enter username:" name
if [ name = sunny ]
then
echo "hello Sunny is available. "
fi
echo "Sunny is busy-remaining line code"
So inside a square bracket, I am doing arithmetic operation right so why here do I need to use the $ symbol to get the name value.
Note If I'll use if [ $name = sunny ] I'm getting expected result.
Any help/suggestion on this would be highly appreciated.
The rule is relatively simple: $ and spaces are optional in arithmetic context, but not in string contexts.
This is because if you expect a number and see foo, you can safely assume that it must be a variable because it sure isn't a number. This is not possible for strings.
Arithmetic context includes:
Arithmetic expansion $((here)) and arithmetic commands ((here))
Integer comparators in [[ .. ]] (but not [ .. ]), such as [[ here -eq here ]]§. Note in particular that = is a string comparator.
Values assigned to variables declared as integers: declare -i foo=here§
Indices of indexed arrays: ${array[here]}
Arguments to let: let here§
Some other more niche constructs like ${str:here:here}, $[here]
In your case, you are using the test command aka [, which (mostly) does not treat anything as an arithmetic expression. This is why you need the $ to differentiate between the literal string name and the value of the variable name.
§ These words are delimited by spaces so one would terminate the expression, but this does not change the fact that spaces are optional. They just need to be escaped to be considered part of the expression.
I did not have to write any bash script before. Here is what I need to do.
My script will be run with a set of string arguments. Number of stings will be more than 8. I will have to concatenate strings 9 and onward and make a single string from those. Like this...
myscript s1 s2 s3 s4 s5 s6 s7 s8 s9 s10....(total unknown)
in the script, I need to do this...
new string = s9 + s10 + ...
I am trying something like this...(from web search).
array="${#}"
tLen=${#array[#]}
# use for loop to read string beyond 9
for (( i=8; i<${tLen}; i++ ));
do
echo ${array[$i]} --> just to show string beyond 9
done
Not working. It prints out if i=0. Here is my input.
./tastest 1 2 3 4 5 6 7 8 A B C
I am expecting A B C to be printed. Finally I will have to make ABC.
Can anyone help?
It should be a lot simpler than the looping in the question:
shift 8
echo "$*"
Lose arguments 1-8; print all the other arguments as a single string with a single space separating arguments (and spaces within arguments preserved).
Or, if you need it in a variable, then:
nine_onwards="$*"
Or if you can't throw away the first 8 arguments in the main shell process:
nine_onwards="$(shift 8; echo "$*")"
You can check that there are at least 9 arguments, of course, complaining if there aren't. Or you can accept an empty string instead — with no error.
And if the arguments must be concatenated with no space (as in the amendment to the question), then you have to juggle with $IFS:
nine_onwards="$(shift 8; IFS=""; echo "$*")"
If I'm interpreting the comments from below this answer correctly, then you want to save the first 8 arguments in 8 separate simple (non-array) variables, and then arguments 9 onwards in another simple variable with no spaces between the argument values.
That's trivially doable:
var1="$1"
var2="$2"
var3="$3"
var4="$4"
var5="$5"
var6="$6"
var7="$7"
var8="$8"
var9="$(shift 8; IFS=""; echo "$*")"
The names don't have to be as closely related as those are. You could use:
teflon="$1"
absinthe="$2"
astronomy="$3"
lobster="$4"
darkest_peru="$5"
mp="$6"
culinary="$7"
dogma="$8"
concatenation="$(shift 8; IFS=""; echo "$*")"
You don't have to do them in that order, either; any sequence (permutation) will do nicely.
Note, too, that in the question, you have:
array="${#}"
Despite the name, that creates a simple variable containing the arguments. To create an array, you must use parentheses like this, where the spaces are optional:
array=( "$#" )
# Create a 0-index-based copy of the array of input arguments.
# (You could, however, work with the 1-based pseudo array $# directly.)
array=( "${#}" )
# Print a concatenation of all input arguments starting with the 9th
# (starting at 0-based index 8), which are passed *individually* to
# `printf`, due to use of `#` to reference the array [slice]
# `%s` as the `printf` format then joins the elements with no separator
# (and no trailing \n).
printf '%s' "${array[#]:8}"
# Alternative: Print the elements separated with a space:
# Note that using `*` instead of `#` causes the array [slice] to be expanded
# to a *single* string using the first char. in `$IFS` as the separator,
# which is a space by default; here you could add a trailing \n by using
# '%s\n' as the `printf` format string.
printf '%s' "${array[*]:8}"
Note that array="${#}" does not create an array - it simply creates a string scalar comprising the concatenation of the input array's elements (invariably) separated by a space each; to create an array, you must enclose it in (...).
To create a space-separated single string from the arguments starting with the 9th enclosed in double quotes, as you request in your follow-up question, use the following:
printf -v var10 '"%s"' "${array[*]:8}"
With the last sample call from your question $var10 will then contain literal "A B C", including the double quotes.
As for assigning arguments 1 through 8 to individual variables.:
Jonathan Leffler's helpful answer shows how to save the first 8 arguments in individual variables.
Here's an algorithmic alternative that creates individual variables based on a given name prefix and sequence number:
n=8 # how many arguments to assign to individual variables
# Create n 'var<i>' variables capturing the first n arguments.
i=0 # variable sequence number
for val in "${array[#]:0:n}"; do
declare "var$((++i))=$val" # create $var<i>, starting with index 1
done
# Print the variables created and their values, using variable indirection.
printf "\nvar<i> variables:\n"
for varName in "${!var#}"; do
printf '%s\n' "$varName=${!varName}"
done
You are close - something like this would work:
array=( ${*} )
# use for loop to read string beyond 9
for (( i=8; i<${#array[*]}; i++ ));
do
echo -n ${array[$i]}
done
I just want to know the reason if i use the (.) instead i got the result but + is doing arhtematic addition but how is that ASCII addition
my $string = "ZZ";
my $appendstring = $string+1;
print $appendstring;
output
1
Expeccting
ZZ1
First of all, your question is very unclear, and your "example" (if you want to call it that) does not match reality, but in an effort to help whoever stumbles across this question in the future, I'm going to venture an answer anyway.
Let's clear up your example first:
$ perl -lwe '$x = "ZZ"; print $x + 1;'
Argument "ZZ" isn't numeric in addition (+) at -e line 1.
1
What I think you might have meant was:
$ perl -lwe '$x = "ZZ"; print ++$x;'
AAA
And the reason for that is explained in perlop:
The auto-increment operator has a little extra builtin magic to it. If
you increment a variable that is numeric, or that has ever been used
in a numeric context, you get a normal increment. If, however, the
variable has been used in only string contexts since it was set, and
has a value that is not the empty string and matches the pattern
/^[a-zA-Z]*[0-9]*\z/, the increment is done as a string, preserving
each character within its range, with carry.
Edit: your updated question isn't any clearer than your original question, but now I think you're asking about string concatenation, which means you want the string concatenation operator: .
$ perl -lwe '$x = "ZZ"; print $x . 1;'
ZZ1
There is, however, a special case where you can use a string with the numeric addition operator and not generate a warning:
$ perl -lwe '$x = "0 but true"; print $x + 1;'
1
You also mentioned "ASCII addition", but I have no idea what that is or what you mean by that.
According to this
this is the way to concatenate
use strict;
use warnings;
my $x = "4T";
my $y = 3;
print $x . $y; # 4T3
but if you do this:
print $x + $y; # 7
# Argument "4T" isn't numeric in addition (+) at ...
Whenever you use the "+" perl tries to convert both values to numeric, if you provide a string and a number or 2 strings it'll take these as 0 and sum them.
http://ideone.com/0LyEij
I am writing a script that takes a parameter with '~' delimiter and after splitting the string I want to insert the values into the array. I have quite a few posts on this problem and I am almost there but there a case where it fails. Here are the details.
myScript.sh
#!/bin/bash
tmpIFS=$IFS
IFS="~"
array=($1)
IFS=$tmpIFS
echo "${#array[#]}"
Executions
$ ./myScript.sh "A~B"
$ 2
Which is what I want. But when I do
$ ./myScript.sh "A~"
$ 1
I was expecting to have a array of size 2 again and the last cell to be an empty string.
How can I achieve that?
What I am trying to achieve in general with this script is to perform an http request using curl by passing 10 query parameters in it. Instead of having 10 parameters to my script I was thinking to get the data as one parameter delimited by a character in a specified order.
Thanks
The ~ are handled like white spaces in your expression, so the behavior makes sense with shell expansion rules. You can use the following workaround:
array=($1"")
To understand why this works, consider it with spaces (unchanged IFS): Assume $1 is A B C, then
array=($1)
expands to
array=(A B C )
which is an array of three elements. On the other hand,
array=($1"")
expands to
array=(A B C "")
which has four. If there is no space at the end of $1, this expands to
array=(A B C"")
which is the same as (A B C) again.
use ./script "A~ " then the last element is "empty".
I have a string which holds a decimal value in it and I need to convert that string into a floating point variable. So an example of the string I have is "5.45" and I want a floating point equivalent so I can add .1 to it. I have searched around the internet, but I only see how to convert a string to an integer.
You don't need to convert it at all:
% perl -e 'print "5.45" + 0.1;'
5.55
This is a simple solution:
Example 1
my $var1 = "123abc";
print $var1 + 0;
Result
123
Example 2
my $var2 = "abc123";
print $var2 + 0;
Result
0
Perl is a context-based language. It doesn't do its work according to the data you give it. Instead, it figures out how to treat the data based on the operators you use and the context in which you use them. If you do numbers sorts of things, you get numbers:
# numeric addition with strings:
my $sum = '5.45' + '0.01'; # 5.46
If you do strings sorts of things, you get strings:
# string replication with numbers:
my $string = ( 45/2 ) x 4; # "22.522.522.522.5"
Perl mostly figures out what to do and it's mostly right. Another way of saying the same thing is that Perl cares more about the verbs than it does the nouns.
Are you trying to do something and it isn't working?
Google lead me here while searching on the same question phill asked (sorting floats) so I figured it would be worth posting the answer despite the thread being kind of old. I'm new to perl and am still getting my head wrapped around it but brian d foy's statement "Perl cares more about the verbs than it does the nouns." above really hits the nail on the head. You don't need to convert the strings to floats before applying the sort. You need to tell the sort to sort the values as numbers and not strings.
i.e.
my #foo = ('1.2', '3.4', '2.1', '4.6');
my #foo_sort = sort {$a <=> $b} #foo;
See http://perldoc.perl.org/functions/sort.html for more details on sort
As I understand it int() is not intended as a 'cast' function for designating data type it's simply being (ab)used here to define the context as an arithmetic one. I've (ab)used (0+$val) in the past to ensure that $val is treated as a number.
$var += 0
probably what you want. Be warned however, if $var is string could not be converted to numeric, you'll get the error, and $var will be reset to 0:
my $var = 'abc123';
print "var = $var\n";
$var += 0;
print "var = $var\n";
logs
var = abc123
Argument "abc123" isn't numeric in addition (+) at test.pl line 7.
var = 0
Perl really only has three types: scalars, arrays, and hashes. And even that distinction is arguable. ;) The way each variable is treated depends on what you do with it:
% perl -e "print 5.4 . 3.4;"
5.43.4
% perl -e "print '5.4' + '3.4';"
8.8
In comparisons it makes a difference if a scalar is a number of a string. And it is not always decidable. I can report a case where perl retrieved a float in "scientific" notation and used that same a few lines below in a comparison:
use strict;
....
next unless $line =~ /and your result is:\s*(.*)/;
my $val = $1;
if ($val < 0.001) {
print "this is small\n";
}
And here $val was not interpreted as numeric for e.g. "2e-77" retrieved from $line. Adding 0 (or 0.0 for good ole C programmers) helped.
Perl is weakly typed and context based. Many scalars can be treated both as strings and numbers, depending on the operators you use.
$a = 7*6; $b = 7x6; print "$a $b\n";
You get 42 777777.
There is a subtle difference, however. When you read numeric data from a text file into a data structure, and then view it with Data::Dumper, you'll notice that your numbers are quoted. Perl treats them internally as strings.
Read:$my_hash{$1} = $2 if /(.+)=(.+)\n/;.
Dump:'foo' => '42'
If you want unquoted numbers in the dump:
Read:$my_hash{$1} = $2+0 if /(.+)=(.+)\n/;.
Dump:'foo' => 42
After $2+0 Perl notices that you've treated $2 as a number, because you used a numeric operator.
I noticed this whilst trying to compare two hashes with Data::Dumper.