3

I just found out about piping stdout into Perl, and I was amazed that you could even do this:

[user@folder] $ echo print 1/3 | perl
0.33333[user@folder] $

From what I understand, you're putting the print command into Perl, and doing a floating point calculation using Perl's code. Please correct me. However, every time I do this, I get an answer that has no newline character. I've searched everywhere and I just can't keyword the terms specific enough to create the answer.

Here's a link to what I'm talking about, under poster Thor: How do I use floating-point division in bash?

He gave an amazing answer, but I couldn't comment or message the user, so I've decided to create a new question here.

I'm still trying to wrap my head around how this is working, variables as well.

$ three=3
$ echo $three/3 | perl
1[user@folder] $

Bonus question:
It started out as me just trying to get bash to output floating point numbers in arithmetic operations. I don't get why bc can't return a float. Supposedly it can, but it just isn't working for me.

Ideally:

$ echo 1/3 | bc
0
$

should return .333 and not 0. I'm delegating to a tool, bc, and bc is supposed to be able to do floats. I just don't understand what's going on.

Community
  • 1
  • 1
Tom
  • 919
  • 3
  • 9
  • 22
  • adding an \n character like: "echo print 1/3 \n" gives me some weird error that I don't have the qualifications to decipher – Tom Dec 11 '15 at 05:25
  • 1
    Ideally that `bonus` question should have been a new so question – sjsam Dec 11 '15 at 05:35
  • I wanted to save space and be efficient to not take up too much space. This entire endeavor is just me trying to figure out shorter ways to print calculated lines without having to resort to: echo $number $number2 | awk '{print $1/$2}' – Tom Dec 11 '15 at 05:36
  • 1
    Too much space huh. lol ;) – sjsam Dec 11 '15 at 05:37
  • If you need floating point then maybe you are using the wrong shell. Consider the Korn shell instead, which supports floating point. – cdarke Dec 11 '15 at 07:36
  • @Tom :`bc` will be able to do floats but not out of the box. – sjsam Dec 11 '15 at 10:37

2 Answers2

6

Perl

Use the -l option (see perldoc perlrun):

$ echo print 1/3 | perl -l
0.333333333333333
$

It adds newlines automatically. The documentation says:

-l[octnum]

enables automatic line-ending processing. It has two separate effects. First, it automatically chomps $/ (the input record separator) when used with -n or -p. Second, it assigns $\ (the output record separator) to have the value of octnum so that any print statements will have that separator added back on. If octnum is omitted, sets $\ to the current value of $/. For instance, to trim lines to 80 columns:

   perl -lpe 'substr($_, 80) = ""'

Note that the assignment $\ = $/ is done when the switch is processed, so the input record separator can be different than the output record separator if the -l switch is followed by a -0 switch:

   gnufind / -print0 | perl -ln0e 'print "found $_" if -p'

This sets $\ to newline and then sets $/ to the null character.


Shell

The shell expands shell variables, so there shouldn't be a surprise at this:

$ three=3
$ echo print $three/3 | perl -l
1
$ echo print $three/3
print 3/3
$

bc

For your bonus question:

$ echo 1/3 | bc -l
.33333333333333333333
$

It is pure fluke that the option is -l again. This time, it means 'load the library', and coincidentally sets the scale to 20, which is why there are 20 decimal digits shown.

Incidentally, a quick way to get π to a large number of decimal places is:

$ echo '4*a(1)' | bc -l
3.14159265358979323844
$ echo 'scale=40; 4*a(1)' | bc -l
3.1415926535897932384626433832795028841968
$

The function a, loaded from the library by the -l option, is for 'arctan'. I observe that at least 3 sources from a Google search 'pi 40 digits' suggests that it should be: 3.1415926535 8979323846 2643383279 5028841971 — which suggests that there's an error of 3 counts in the 40th digit from bc.

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Thank you. I just knew there had to be a simple switch like that. So by extension, is there a way to get stdnin when giving it to perl as well? Like, if I wanted to do perl (print 3/3) -l. Is it possible to call perl and give it your own input instead of having it accept the std-out of a pipe? – Tom Dec 11 '15 at 18:50
  • Are you looking for `perl -e 'print 1/3' -l`? Possibly with `-n` or `-p` as well. – Jonathan Leffler Dec 11 '15 at 21:38
  • So why exactly do I have to do -e? When I feed it the output of a previous pipeline (like echo print test) does perl just inherently interpret it as a -e command? otherwise, perl ____ will seek a file? edit: it seems like the -e switch "turns on" the command line – Tom Dec 11 '15 at 22:54
  • You will need to digest `perldoc perlrun` sometime. With `-e`, Perl accepts the following argument as the 'script' to be run. Alternatively, if you provide a script name (`perl script.pl`) then that is the script to run. If neither of those applies, Perl reads the script from standard input. The `print 1/3` code starts to creak at this point; it is a bit too simplistic. But the principles appply; Perl reads the script from a `-e` argument, a file argument, or standard input. – Jonathan Leffler Dec 11 '15 at 22:57
  • Hm, so in theory, I can funnel an entire perl script through the -e argument in between the single quotes, and it will compile and run as if it was some sort of Python IDLE, but in the bash environment? – Tom Dec 11 '15 at 23:02
  • Yup, and you'll be grateful, probably, that Perl doesn't care about newlines etc. You can write a multiline script too. And Perl's arbitrary quoting conventions (e.g. `q{}` and `qq{}` — or, for the malicious, like me, ``q"${single}-${quoted} `material`"``) also help. You don't need a shebang (though it does no harm). – Jonathan Leffler Dec 11 '15 at 23:04
1

With bashcalculator ie bc this is how you should do it :

echo " scale=4; 1 / 3" | bc

where the value for scale defines the number of floating point numbers.

sjsam
  • 21,411
  • 5
  • 55
  • 102