In this chapter, we’ll look at various one-liners for performing calculations, such as
- finding minimum and maximum elements
- counting
- shuffling
- permuting words
- calculating dates and numbers.
You’ll also learn about the -a, -M, and -F command-line arguments, the $, special variable, and the @{[ ... ]} construction that lets you run code inside double quotes.
4.1 Check if a number is a prime(质数)
perl -lne '(1x$_) !~ /^1?$|^(11+?)\1+$/ && print "$_ is prime"'
比如说,数字7,字串是1111111,匹配11(11)+匹配不了,尝试111(111)+也不行,1111(1111)+也不行,所以是质数;同理,数字9,字串是111111111,匹配11(11)+匹配不上,但是匹配111(111)+可以,所以9是质数。
4.2 Print the sum of all fields on each line
perl -MList::Util=sum -alne 'print sum @F'
And you wish to find the sum of all these numbers. You can simply specify : as an argument to the -F switch, like this:
perl -MList::Util=sum -F: -alne 'print sum @F'
4.3 Print the sum of all fields on all lines
perl -MList::Util=sum -alne 'push @S,@F; END { print sum @S }'
Unfortunately, summing all fields on all lines using this solution creates a massive @S array. A better solution is to keep only the running sum, like this:
perl -MList::Util=sum -alne '$s += sum @F; END { print $s }'
4.4 Shuffle all fields on each line
echo a b c d | perl -MList::Util=shuffle -alne 'print "@{[shuffle @F]}"'
to this:
echo a b c d | perl -MList::Util=shuffle -alne 'print shuffle @F'
You can use the $, special variable to change the separator between array elements when they’re printed. For example, here’s what happens when I change the separator to a colon:
echo a b c d | perl -MList::Util=shuffle -alne '$,=":"; print shuffle @F'
You can also use the join function to join the elements of @F with a space:
perl -MList::Util=shuffle -alne 'print join " ", shuffle @F'
4.5 Find the numerically smallest element (minimum element) on each line
perl -MList::Util=min -alne 'print min @F'
4.6 Find the numerically smallest element (minimum element) over all lines
perl -MList::Util=min -alne '@M = (@M, @F); END { print min @M }'
If you’re using Perl 5.10 or later, you can do the same thing with this one-liner:
perl -MList::Util=min -alne '$min = min($min // (), @F); END { print $min }'
4.7 Find the numerically largest element (maximum
element) on each line
perl -MList::Util=max -alne 'print max @F'
4.8 Find the numerically largest element (maximum
element) over all lines
perl -MList::Util=max -alne '@M = (@M, @F); END { print max @M }'
If you’re using Perl 5.10 or later, you can use the // operator to shorten this one-liner:
perl -MList::Util=max -alne '$max = max($max // (), @F); END { print $max }'
4.9 Replace each field with its absolute value
perl -alne 'print "@{[map { abs } @F]}"'
4.10 Print the total number of fields on each line
perl -alne 'print scalar @F'
4.11 Print the total number of fields on each line,
followed by the line
perl -alne 'print scalar @F, " $_"'
4.12 Print the total number of fields on all lines
perl -alne '$t += @F; END { print $t }'
4.13 Print the total number of fields that match a pattern
perl -alne 'map { /regex/ && $t++ } @F; END { print $t || 0 }'
Looping would be a better approach:
perl -alne '$t += /regex/ for @F; END { print $t }'
Another way to do this is to use grep in the scalar context:
perl -alne '$t += grep /regex/, @F; END { print $t }'
4.14 Print the total number of lines that match a pattern
perl -lne '/regex/ && $t++; END { print $t || 0 }'
4.15 Print the number π
perl -Mbignum=bpi -le 'print bpi(21)'
The bignum library also exports the constant π, precomputed to 39 decimal places:
perl -Mbignum=PI -le 'print PI'
4.16 Print the number e
perl -Mbignum=bexp -le 'print bexp(1,21)'
For example, you could print the value of e 2 to 30 decimal places:
perl -Mbignum=bexp -le 'print bexp(2,31)'
As with π, bignum also exports the constant e precomputed to 39 decimal places:
perl -Mbignum=e -le 'print e'
4.17 Print UNIX time (seconds since January 1, 1970,00:00:00 UTC)
perl -le 'print time'
4.18 Print Greenwich Mean Time and local computer time
perl -le 'print scalar gmtime'
The built-in localtime function acts like gmtime, except it returns the computer’s local time when it’s used in the scalar context:
perl -le 'print scalar localtime'
![](https://img.haomeiwen.com/i7600498/f3b75125e0066b71.png)
You can slice this list (that is, extract elements from it) or print individual elements if you need just some part of the information it contains. For example, to print H:M:S, slice the elements 2, 1, and 0 from localtime, like this:
perl -le 'print join ":", (localtime)[2,1,0]'
To slice elements individually, specify a list of elements to extract, for instance [2,1,0]. Or slice them as a range:
perl -le 'print join ":", (localtime)[2..6]'
You can also use negative indexes to select elements from the opposite end of a list:
perl -le 'print join ":", (localtime)[-2, -3]'
4.19 Print yesterday’s date
perl -MPOSIX -le ' @now = localtime; $now[3] -= 1; print scalar localtime mktime @now'
4.20 Print the date 14 months, 9 days, and 7 seconds ago
perl -MPOSIX -le ' @now = localtime; $now[0] -=7; $now[3] -=9; $now[4] -= 14; print scalar localtime mktime @now'
4.21 Calculate the factorial
perl -MMath::BigInt -le 'print Math::BigInt->new(5)->bfac()'
Another way to calculate a factorial is to multiply the numbers from 1 to n together:
perl -le '$f = 1; $f *= $_ for 1..5; print $f'
4.22 Calculate the greatest common divisor
perl -MMath::BigInt=bgcd -le 'print bgcd(20,60,30)'
To calculate the gcd from a file or user’s input, use the -a commandline argument and pass the @F array to the bgcd function:
perl -MMath::BigInt=bgcd -anle 'print bgcd(@F)'
4.23 Calculate the least common multiple
perl -MMath::BigInt=blcm -le 'print blcm(35,20,8)'
4.24 Generate 10 random numbers between 5 and 15 (excluding 15)
perl -le 'print join ",", map { int(rand(15-5))+5 } 1..10'
4.25 Generate all permutations of a list
perl -MAlgorithm::Permute -le ' $l = [1,2,3,4,5];$p = Algorithm::Permute->new($l);print "@r" while @r = $p->next'
4.26 Generate the powerset
perl -MList::PowerSet=powerset -le ' @l = (1,2,3,4,5); print "@$_" for @{powerset(@l)} '
4.27 Convert an IP address to an unsigned integer
perl -le '$i=3; $u += ($_<<8*$i--) for "127.0.0.1" =~ /(\d+)/g; print $u'
Here are some more one-liners:
perl -le '$ip="127.0.0.1";$ip =~ s/(\d+)\.?/sprintf("%02x", $1)/ge;print hex($ip)'
You can also use unpack:
perl -le 'print unpack("N", 127.0.0.1)'
If you have a string with an IP (rather than a vstring), you first have to convert it to byte form with the function inet_aton:
perl -MSocket -le 'print unpack("N", inet_aton("127.0.0.1"))'
4.28 Convert an unsigned integer to an IP address
perl -MSocket -le 'print inet_ntoa(pack("N", 2130706433))'
网友评论