Why does OpenBSD still include Perl in its base installation?
marc.info
marc.info
If my bash script gets much beyond simple looping, I switch to Perl.
CPAN (http://www.cpan.org/index.html) is quite large and has libraries to do almost everything you can imagine.
I am not sure if CPAN or pip has more libraries though.
>> And it's generally easier to read/write.
Python looks nicer, but not everyone likes significant whitespace.
The Python 2 to 3 change has also caused some adoption issues. The Perl 4 to 5 happened quite a while ago. Perl 5 has been integral to Unix-like systems since the web went mainstream.
Perl 5 lives on and is still developed and maintained: https://www.perl.org/get.html
Perl 6 became Raku: https://www.raku.org/
Python 2 is still in use, but officially deprecated: https://www.python.org/doc/sunset-python-2/
You could probably start a business maintaining a Python 2 distribution and selling support to businesses and organizations that rely on Python 2 and are not in a position to upgrade: https://www.activestate.com/blog/python-2-eol-report-card-is...
So do /bin/sh and /bin/bash scripts.
/usr/bin/python scripts IME depend on what /usr/bin/python points to; some break/broke due to the python 2 to python 3 switching, which hasn't been as backwards-compatible as previous examples have.
"#!/usr/bin/env bash" or "#!/usr/bin/env python" are the recommended ways to run both, AFAIK.
Most (all?) commercial Unix I have used also don't have bash, but those systems are pretty dead these days.
OpenBSD's fork of ksh is actually really good so I typically feel no reason to ever install bash on there. On others, the default shell kinda sucks and I tend to install bash. In particular the old /bin/sh on older Unix tends to be worse at interactive use and not support some constructs like {a,b}
I'm typing this on FreeBSD. It's in /usr/local because it came from ports.
$ which bash
/usr/local/bin/bash
Now I try my OpenBSD machine. It's not installed at all. $ which bash
which: bash: Command not found.Why would you expect it to be?
dash is a POSIX shell:
* https://en.wikipedia.org/wiki/Almquist_shell#dash
Even when called as /bin/sh, which implies Bourne/POSIX behaviour, bash leaks all kinds of functionality into the environment such that if you tru to run your "/bin/sh" script on another shell it may not work.
We had all sorts of issues when Debian made the switch: we had to tell people either (a) fix the code, or (b) change your shebang to bash.
If you want Bash behaviour call bash. It's like when I type in "vi" in the command line and I get an editor with all sorts of colours: WTF? If I wanted Vim I would have typed in "vim", but for editing a small file all I need is POSIX vi without the dog and pony display show. /rant
Sometimes I used to create such a symlink myself but I don't use or run a lot of python day to day so my current systems do not have this.
Consider this:
my %h = (); # an empty hash
$h{'foo'}[3]{'bar'} = 'bletch';
Now my hash contains one entry with key 'foo'. That entry is a reference to an array of 4 elements. The first 3 elements of that array are undef, and the 4th is a reference to another hash. That hash contains one entry with key 'bar' and value 'bletch'.In a lot of other languages you would need to explicitly allocate an array of at least 4 elements for $h{'foo'}, and then explicitly allocate a hash for $h{'foo'}[3].
With Perl they just come into existence when you try to store something in them.
Is this always good? No. There are many problems where this automatic reification would just hide bugs. If you are, for example, processing data that is supposed to be clean and well specified then parsing it into explicitly allocated data structures that match what you expect and will throw errors if you try to put something in out of range is great.
But when you are dealing with data that is not clean and not well specified, being able to get it all in your data structures easily even when there is something wrong or inconsistent in the data can be great. Get it all in, and then you can run cleanup code on it looking for unexpected things, and fixing them or alerting you that you need to add more cases to the fixing code.
There's a similar thing on the reading side of Perl data structures. Try to access a hash via a key that does not exist, or an array by an index past the end? You simply get back undef.
Is this always good. Like automatic reification, the answer is no. There are many problems where it would be a grave error if the code tried to access an element of a hash or array that it had not previously but in there.
For problems where your logic would include a lot of places where you check if an element exists and if it does you add to a total or if it is a non-empty string you include it in something else, the code can be cleaner in a language with Perl's approach. Adding undef to a number is like adding 0, and undef compares as equal to an empty string.
Good thing then that the programmer has the choice to use it or not.
repl>>> no autovivification 'store'
repl>>> my %h
%h = ()
repl>>> $h{'foo'}[3]{'bar'} = 'bletch'
Runtime error: Can't vivify reference at (eval …)
> Is this [returning undef for non-existing keys/indexes] always good. […] the answer is no.Good thing then that the programmer has the choice to use it or not.
repl>>> use Hash::Util 'lock_keys'
repl>>> my %h
%h = ()
repl>>> lock_keys %h
()
repl>>> $h{no_such_key}
Runtime error: Attempt to access disallowed key 'no_such_key' in a restricted hash at (eval …)
repl>>> package Array::Bounded {
use Tie::Array;
use base 'Tie::StdArray';
sub FETCH {
my ($self, $index) = @_;
die "Attempt to access out of bounds index $index in a restricted array" if $index >= $self->@*;
return $self->[$index];
}
}
repl>>> tie my @a, 'Array::Bounded'
repl>>> @a = ('a'..'f')
@a = ('a'..'f')
repl>>> $a[5]
f
repl>>> $a[6]
Runtime error: Attempt to access out of bounds index 6 in a restricted array at (eval …)If you want to make a comparison though, I think perl vs sed is a more meaningful one. You can do things that's possible in sed with perl one-liners in a more portable way. It's installed by default on major Linux distributions, and even works on macOS without the GNU vs BSD incompatibilities.
Unfortunately, simple scripts that are found to be useful often grow into complex scripts.
A few weeks ago, I wanted to write some functionality that seemed "simple" enough to be a good fit for make+bash. A week later, I ended up tossing the whole thing and rewriting it in python.
It is useful and not difficult to be productive in, but does manage to feel more unnatural than both of those though.
My scripts end up longer and more verbose typically (I might just not be great at Python) but also a lot more maintainable (I am not great at writing maintainable Perl and I use Python more often).
I also use Node.js for this a lot because of the ecosystem containing so many accessible scripts and dependency management while not great is heaps better than most other ecosystems.
Of course OpenBSD can't do that with Python rather then Perl (as explained in that email). They have a different set of constraints. I am only saying in practice I have found Python to be the better alternative for my personal stuff.
I've got 20 year old python scripts the have been upgraded over the years that are still maintainable, easy to read and do the job just fine.
Take good old fizzbuzz. Want to write it clear and simple in Perl? No problem:
for (my $n = 1; $n <= 100; ++$n) {
if ($n % 15 == 0) { print "fizzbuzz\n"; }
elsif ($n % 3 == 0) { print "fizz\n"; }
elsif ($n % 5 == 0) { print "buzz\n"; }
else { print "$n\n" };
}
Want to get clever and complex in Python? Here you go: def fizzbuzz(n, *args):
cur = ['' for x in range(1,n+1)]
for m, postfix in args:
cur = [y+postfix if x%m==0 else y for x, y in zip(range(1,n+1), cur)]
cur = [str(x) if y == '' else y for x, y in zip(range(1,n+1), cur)]
return cur
print("\n".join(fizzbuzz(100, (3, 'fizz'), (5, 'buzz'))))
Of course you could do an unclear and overly clever Perl version, too, or a clear and simple Python version. say "foo";
was equivalent to print "foo", "\n";Perl obviously even lets experts shoot themselves in the foot on the simplest code, see the fizzbuzz above me, While a beginner would never write the complex python version that was shown, not even by accident.
An example of a langauge at the extreme other end of the spectrum would probably be APL. It's indecipherable gibberish to me every time I look at it, but I'm not even an APL amateur, much less professional, and that language seems built to be used by people that are very familiar with it. Is that wrong? No, they just aren't optimizing for learnability and community growth, as Python does, instead opting to make it as simple and useful as possible for experts to get what they need accomplished.
You can counter by saying that most code is read more than it's written, so readability is more important, and to that I would say that it depends on the type of code (scripting languages lend themselves to a lot of one-off scripts), and that readability is also a function of experience. If you want your code easily readable my amateurs, then keeping the capabilities you can use to those an amateur can understand is beneficial. If you want your code readable and understandable by experienced programmers, use constructs and control flows that they are experienced with, which is a much wider set of capabilities usually (if the language supports them).
I also wouldn't keep all the blocks on the same line, but it can be forgiven in a comment box.
I actually had that at first...
> I might even skip the `== 0` but just saying `(! $n % 15)`
...and that too. I changed them to be more likely to be obvious to even someone who has never seen Perl before. A lot of languages besides Perl have a "for" loop variant that is like a C "for" loop.
The formatting was indeed because it was in a comment box. I didn't want to take up too much vertical space on the page.
for (1..100) {
if (not $_ % 15) { say 'FizzBuzz' }
elsif (not $_ % 3) { say 'Fizz' }
elsif (not $_ % 5) { say 'Buzz' }
else { say }
}
Just sayingIn that I write it once and 20 years later it still works even though I upgraded the compiler many times.
Is there any non-shell scripting language that makes it as easy as shell to run external commands, redirect I/O etc.? I don't know of any. (Perhaps that is the very definition of a shell.)
I think a good way of doing this would be to make a shell that has more expressive power and a clearer syntax.
Would Scsh count?
The general syntax, operators, etc, are close, and familiar things like stat(), gethostbyname(), etc, work almost the same.
Edit: One of their Perl scripts for reference: https://github.com/openbsd/src/blob/b66614995ab119f75167daaa...
And pkg_add, which has quite a lot of Perl: https://github.com/openbsd/src/tree/master/usr.sbin/pkg_add
I'm not familiar with these types of things, can someone shed some light on this comment?
> awk would kind of work, except it's not that readable
I don't think I've ever heard someone say a plus side of perl is it's "readability". And this is coming from someone who really enjoys perl
> As for the license, python’s license appears fairly similar to Perl’s artistic license. I would worry a bit about the strong terms in
>> 6. This License Agreement will automatically terminate upon a material breach of its terms and conditions.
> for which no equivalent is visible in Perl’s license.
[0]: https://marc.info/?l=openbsd-misc&m=157781106212088&w=2
edit: why the downvote? It states explicitly that the license is only granted as long as its requirements (T&Cs) are upheld. Which seem obvious to me, assuming the license does have conditions?
Though I guess it's less obvious to the legal profession as the MPL has a similarly explicit clause (5.1, and 5.2 also terminates the license if you initiate patent infringement litigation against "against any entity", which seems oddly broad)
It's strange though, they also have
> 8. By copying, installing or otherwise using Python 3.8.3, Licensee agrees to be bound by the terms and conditions of this License Agreement.
which feels very 90ies-EULA-style. If I download ("copy") an archive that contains Python, I should be bound by that License Agreement? Since there's not severability clause, wouldn't that just void the limitations they've set?
In any case, it's being compared to Awk here.
Or Latin:
https://metacpan.org/pod/distribution/Lingua-Romana-Perligat...
Or Klingon:
https://metacpan.org/pod/Lingua::tlhInganHol::yIghun
Or Poetry:
https://en.wikipedia.org/wiki/Black_Perl
Perl could be considered too flexible.
> 6. This License Agreement will automatically terminate upon a material breach of its terms and conditions.
which I'd have assumed implicit to pretty much every license — or at least every license with conditions — but I guess not if the PSF (or Mozilla which has a similar clause in the MPL) felt the need to specify it explicitly.
I don’t actually know, though. It just doesn’t seem like a safe assumption.
> I wouldn’t assume so. Contracts often specify the opposite, that violation of one term does not void or negate the contract.
I have not seen this language. Typically violating a condition of the contract means you are in breach. Sometimes remedies to certain breaches are enumerated in the contract.
The language about one item not voiding or negating the whole is often in regard to the legality of the contract, something like below (excerpted from an MSA from a client):
> If any term, condition, or provision in this Agreement is found to be invalid, unlawful, or unenforceable to any extent, the parties shall endeavor in good faith to agree to such amendments that will preserve, as far as possible, the intentions expressed in this Agreement. If the parties fail to agree on such an amendment, such invalid term, condition, or provision shall be severed from the remaining terms, conditions and provisions, which shall continue to be valid and enforceable to the fullest extent permitted by law.
This is basically saying if one term in the contract is voided, it does not void the whole contract. This is very different from "if you breach one term, the contract is not considered breached".
Certainly, you can use GPL software with a BSD licensed system, and you can distribute GPL packages to be installed on a BSD licensed system, but if you include GPL software in a BSD system, it's no longer a BSD system.
If the license prevents otherwise useful software from being used in the base system, what would you call it?
The situation here is different: it’s about distribution, and it’s up to you, the distributor, to decide whether you want to include restrictively licensed software or not. With license incompatibility, you don’t get that choice: you just cannot legally distribute it.
The kind of people who write unreadable code have long since moved on to write unreadable code in trendier languages and legacy critical code has long since been cleaned up if its of value.
Unreadable Perl is no longer an issue in 2020.
Can someone explain the difference here? OpenBSD is BSD licensed [1]. Python is a BSD-style, permissive free software license which is compatible with the GNU General Public License [2][3]. Licenses are always contentious, but how does this rule Python out? (Granted, the dynamic libraries technical point makes this kind of a moot question.)
[1] https://www.openbsd.org/policy.html
[2] https://docs.python.org/3/license.html
[3] https://en.wikipedia.org/wiki/Python_Software_Foundation_Lic...
It lets you parse INI files in a single call for eg.
Perl has some easy oneliners too. Depending on where I'm working sometimes I don't want to set up an environment.
Two examples I can give in my case are the good old rsnapshot, and CSF firewall
Is it Fedora-specific?
> If you want GNU Parallel to be maintained in the future, and not just wither away like so many other free software tools, you need to help finance the development.
etc
For more details, check out the Arch Linux patches that patch this super-annoying message out:
https://git.archlinux.org/svntogit/community.git/tree/trunk?...
The message appears every time when using GNU parallel unless a very long flag is given or the executable has been patched.
I think it goes against the philosophy of most open source software that comes with Linux distros, where you are given software freely, but pay back by contributing to the overall open source community, if you can and want. (This is my subjective interpretation of the matter).
More info at: https://sources.debian.org/patches/parallel/20161222-1.1/
I wanted to use it but also wanted to respect the wishes of the author, so, as I disagreed with the note, had to use something else.
So if you remove Perl, either you renounce also to include Postgresql in your distro, or you would need to rewrite a non trivial amount of scripts in a different language to restore Postgresql support.
Normally I do not have Perl installed, to conserve space.
NetBSD thankfully has always done without a large scripting language, only recently have they included Lua. I wonder how long it would take to rewrite the OpenSSL perl scripts in lua.
10 years ago
* Perl has a built in taint checking facility which is quite good at preventing the naive use of non-vetted user data; I don't recall whether Tcl has anything similar. https://perldoc.perl.org/perlsec.html
> I was wondering if I need the package manager in the minimal installation of the system as I only use built-in deamons (httpd, sshd) and UNIX utilities (vi, sed)? By package manager I mean pkg_* executables as well as its dependencies (most notably Perl). (The size of /usr/libdata/perl5 is about 50MB on my machine). I just want the minimal installation without any unnecessary scripting language.
> Looking at FreeBSD for a moment it seems like Perl left the base system in May 2002 (18 years ago)
- Acceptable license? MIT
- you need something that builds everywhere. It probably does? At least it compiles with Turbo C 1.0.
- Modicum of security: probably.
Lua is also small compared to Perl, is easily embeddable, and seems to have a sane syntax compared to Perl.
I do understand why they use Perl though, probably more OpenBSD developers/users are familiar with it.
Edit: Sort of makes me wonder why a VERY C-like, small, dynamically typed, scripting language never emerged. Squirrel is kind of close, but not quite what I mean.
Csh (https://en.wikipedia.org/wiki/C_shell) was the de facto standard shell on many Unix systems and still is widely used.
However, it has some issues:
There's been some WIP to also use it for some pkgbase stuff, as well as an ldconfig lua script for use in post-install scripts now that pkg supports post-install.lua.
I've had my eye on a couple of other components that could use a rewrite with flua. A new flua-based replacement for kernel config(8) could be quite excellent, for instance.
Having said that I wrote a bunch of Tcl last year for a speech[1] and the Tcl community is nowadays very small. It was hard to find answers to some questions online: the active period of the community predated Stackoverflow so there's not much on SO. And the library support is very thin compared to the giant Perl/Python/Javascript/... communities. None of these things are reasons why Tcl is bad - I happen to like it and my talk was a success partly because of Tcl - but it may be a problem for OpenBSD to adopt it.
Perl's tainting feature is the only security-related advantage over Tcl that I can think of right now, but it's not used unless you explicitly enable it.
Perl is antithetical to simplicity, often jokingly referred to as "write-only software". Not to mention the myriad of packages that usually end up being brought in (thanks CPAN!).
So, it's a fair question, not just "why is there a perl interpreter?", which is a decent question given openbsd's overall lack of shipping with much; but also "Why are large parts of the glue code written in perl?"
EDIT: I know it's frowned on to talk about downvotes, but I received quite a few and I'm not sure why. Please leave a comment if you're going to flag a comment.
Having pf, bgpd, ospfd, isakmpd etc. included in base for systems I administer are crucial for my daily tasks, while I couldn't care less for node.js. But application developers not dealing with network stuff probably have the opposite needs.
It's not about "which OS is better" but about "which tool is appropriate for the job".
Some person P likes technology X, but they are aware that others consider it a sport to dump on X. A rare article about X comes up in a popular forum. P clicks on it with dread to see how X is being dumped on this time. But it says positive things! P's dread is replaced with optimism. Then P reads the typical dumping-on-X post, which says something like "X is a hideous monstrosity. I fart in its general direction" or "X is antithetical to simplicity, often jokingly referred to as etc". P's dark mood returns and P does as people do when they feel like someone has been unnecessarily cruel and provoking: they press the shun button.
Perl aficionados have a long history of being on the receiving end of passive aggressive language zealots. Usually they are Pythonistas, but others have joined in as well.
You see this in messages that say "perl is a write once language" or "its too complex" or "line noise" or "why is it still alive when X is better" ... Really, its tiring after 25+ years using it. So, in an effort to express a valid and terse critique of the comment, the respondent does the right thing, and down votes the specific comment making those, frankly, inane points.
From there, people draw up interesting theories as to why the passive aggressive behavior was down voted.
The reality. Perl is a modern, highly capable, fast, easy to use language. It is comprehensible by mere mortals, while having powerful features that other languages often attempt to replicate poorly (regex, etc.) It is portable, running the same code across *nix, windows, macos, ... . It is fast[1] (yes really).
It doesn't claim to solve the worlds problems, but is a tremendously useful and portable tool, embedded in many companies products. Specifically, when they need to get something done, and done well, perl in the toolbox is a godsend.
Claims it is dead, hard, slow, incompatible, etc. tend to come from a vocal minority of people with an agenda.
I don't claim my theory is correct. I do believe it fits a very long standing pattern in language advocacy.
For me personally, I use the best tools for the job. Perl is often the right tool, but not always. Sometimes its python. Sometimes Julia. Sometimes C/C++. Rarely these days Fortran (moving to Julia).
This said, I am not going to bash any of the tools I use, or that others use. If visual basic .net works for you, use it. If you need to be portable across systems and OSes, you probably don't want to be writing things in powershell (literally had this conversation at $dayjob a few times over the last few months).
Languages come with dependencies and baggage. You can write great maintainable code in Perl, and terrible not comprehensible code in Perl. As you can in any language. Arguing that one language or the other "enables" you to do this "more easily" is a perfect example of that passive aggressive stance that is not helpful to anyone.
Use the right tool for the job. Perl, more often than not, is the right tool.
[1] https://scalability.org/2020/05/on-optimizing-scripting-lang...
I'm pretty sure you just expressed the same theory in different words...
Quite a few people I know got started with Perl because they were reasonably comfortable with awk, sh, or sed, started to outgrow their sweet spot, and found that perl provided a very natural transition from each of these languages, could do everything those scripts could do in fairly similar ways, and was obviously more powerful.
You cannot however mix GPL code into your BSD code and the resulting work as BSD.
That is completely wrong, you cannot change the license at your will ESPECIALLY from BSD to a GPL. The BSD-Code stays BSD-licensed-code, you can include it into a GPL Project, but NOT change the License, doesn't matter if its from BSD to GPL or vice versa.
Since your not the owner of the code, you have absolutely NO right to change the license.
That said, you're very close to the mark. GPL applies to distributions of the copyrighted work and executables based on it. So, the concern is around an OpenBSD release - they are shipping a full OS with source code and compiled work product. The GPL is "viral" in that you cannot make this release without licensing your whole distribution as GPL. OpenBSD does not want to be GPL, and so does not include GPL-ed code in base.
The inverse is not true. A Linux distribution can include GPL and BSD-licensed code easily, because the BSD license imposes no constraints on redistribution.
Copying BSD code and distributing it under another license (even a commercial one) seems to be totally OK though as long as you put in the correct notices.
That is what GPL is meant to protect against.
GPL enhances user freedom at the expense of restricting what programmers can do.
I fail to see how this is different from what I wrote above (except for the missing word in my post above):
> You cannot however mix GPL code into your BSD code and [distribute] the resulting work as BSD.
We are in verbose (and unnecessary on my part) agreement.
So, your point doesn't hold up even for this case.
I am not sure how important perl is.
Knowing when to shut up is a valuable skill to have.
For Perl 5, you could do worse than going through the _free_ "Modern Perl" book, at http://modernperlbooks.com/books/modern_perl_2016/
Anyhow, I've been reading this for a half-hour or so and I'm struck by how incredibly similar common Perl idioms feel to JavaScript as it is commonly used today. I think part of this familiarity has to do partly with type coercion, partly with destructing assignments, partly with function "context"(as in Perl) as it is commonly deployed in the nodejs ecosystem, partly because of the way default arguments and function passing relates to the default scalar variable in Perl.
I've been playing around with OCaml and Rust a bunch recently, but haven't had any good reason to reach for them "in real life." The fact that Perl is "everywhere" (much the way JavaScript is "everywhere" as a side effect of browsers being ubiquitous), means that I'm likely to start reaching for Perl instead of nodejs when I need to move beyond Bash. It really does seem to be the right tool for the job.
So, a hearty "thank you" for the recommendation.
Thank you for writing this, it seems very well done so far. And thanks for also making it available in the way that you did: I almost certainly wouldn't have played with Perl today without your book, made effortlessly available on my e-reader via Pragmatic. I'm curious why it's not available in physical copy from Pragmatic? And I'm not confident about the correct "buy" link to use to properly support the book.
One sidenote that I hate to mention, but: I couldn't figure out how to open a PR for this or even email someone who would care, but I found a code-typo on the CPAN website: it's instruction to "install via App::cpanminus" and then use with "cpanm name::module" is...an unfortunate early typo on that site.
I believe it is:
https://pragprog.com/cart/add/skus?sku_id=821_820
I'm not confident about the correct "buy" link to use to properly support the book.
It's more valuable to me if you share and enjoy. I give away electronic versions so that it's useful, not to make money from the time I spent writing it.
I found a code-typo on the CPAN website
Is this the page you were reading?
https://cpan.metacpan.org/modules/INSTALL.html
It's not explained on that page, but the distribution App::cpanminus installs a program called cpanm, not cpanminus (as one would expect).