Other What's the go-to scripting language to learn for general purpose-scripting on freebsd?

Python wins hands down if you want something modern, it simply is one of the easiest languages to read and write. While it has many advanced features, you do not need to use them. Even if you come back months or years after you haven't written anything in Python you will probably understand what you have done. Not so with Perl. With Python you have all the means to write simple scripts, and also to grow to major systems, like testing/mocking, debugging, profiling, type hints etc.
Just because you can't use Perl doesn't mean it's a bad language. You can do anything in Perl that you can do in Python (but not vice versa).
 
Same code in Python and Perl by a certain LLM imp.

The same non-subject says that this code "Computes all prime numbers up to an integer limit using the Sieve of Eratosthenes, then prints (1) how many primes exist up to that bound, (2) their sum, (3) the largest gap between consecutive primes in that range, and (4) the last few primes."

Personally, I find the Perl version much more readable.

Python:
#!/usr/bin/env python3
import argparse

def sieve(limit: int) -> list[int]:
    if limit < 2:
        return []
    is_prime = bytearray(b"\x01") * (limit + 1)
    is_prime[0:2] = b"\x00\x00"
    p = 2
    while p * p <= limit:
        if is_prime[p]:
            step = p
            start = p * p
            is_prime[start : limit + 1 : step] = b"\x00" * (((limit - start) // step) + 1)
        p += 1
    return [i for i in range(2, limit + 1) if is_prime[i]]

def main() -> None:
    ap = argparse.ArgumentParser(description="Compute primes up to a limit and print summary statistics.")
    ap.add_argument("--limit", type=int, default=100000, help="Upper bound (inclusive).")
    ap.add_argument("--tail", type=int, default=10, help="How many of the largest primes to print.")
    args = ap.parse_args()

    primes = sieve(args.limit)
    count = len(primes)
    total = sum(primes)
    max_gap = 0
    gap_pair = None

    for a, b in zip(primes, primes[1:]):
        g = b - a
        if g > max_gap:
            max_gap = g
            gap_pair = (a, b)

    print(f"limit={args.limit}")
    print(f"count={count}")
    print(f"sum={total}")
    if gap_pair:
        print(f"max_gap={max_gap} between {gap_pair[0]} and {gap_pair[1]}")
    else:
        print("max_gap=0 (fewer than two primes)")

    tail = primes[-args.tail:] if args.tail > 0 else []
    if tail:
        print("tail:", " ".join(map(str, tail)))

if __name__ == "__main__":
    main()

Perl:
#!/usr/bin/env perl
use strict;
use warnings;
use Getopt::Long;

sub sieve {
    my ($limit) = @_;
    return () if $limit < 2;

    my @is_prime = (0, 0, (1) x ($limit - 1));  # indices 0..$limit
    for (my $p = 2; $p * $p <= $limit; $p++) {
        next unless $is_prime[$p];
        for (my $m = $p * $p; $m <= $limit; $m += $p) {
            $is_prime[$m] = 0;
        }
    }
    my @primes;
    for my $i (2 .. $limit) {
        push @primes, $i if $is_prime[$i];
    }
    return @primes;
}

my $limit = 100000;
my $tail  = 10;
GetOptions(
    "limit=i" => \$limit,
    "tail=i"  => \$tail,
) or die "Usage: $0 [--limit N] [--tail K]\n";

my @primes = sieve($limit);
my $count = scalar @primes;

my $sum = 0;
$sum += $_ for @primes;

my $max_gap = 0;
my ($ga, $gb);
for (my $i = 0; $i + 1 < @primes; $i++) {
    my $g = $primes[$i + 1] - $primes[$i];
    if ($g > $max_gap) {
        $max_gap = $g;
        ($ga, $gb) = ($primes[$i], $primes[$i + 1]);
    }
}

print "limit=$limit\n";
print "count=$count\n";
print "sum=$sum\n";
if ($count >= 2) {
    print "max_gap=$max_gap between $ga and $gb\n";
} else {
    print "max_gap=0 (fewer than two primes)\n";
}

if ($tail > 0 && $count > 0) {
    my $start = $count - $tail;
    $start = 0 if $start < 0;
    print "tail: ";
    print join(" ", @primes[$start .. $count - 1]), "\n";
}
 
Personally, I find the Perl version much more readable.
and I can tell you from my students who arrive and have zero knowledge about programming, 99% would find the Python version more readable. Thats one of the main reason so many universities teach entry level programming in Python, not Perl.
 
I recommend the OP to use lang/bwbasic (Bywater Basic).

[It's a joke. But I'm sure you can do great stuff with it if you learn it.]

BWBasic:
Code:
10 REM ================================================================
20 REM  primes_stats.bas  (BWBasic)
30 REM  Prime statistics via the Sieve of Eratosthenes.
40 REM
50 REM  Outputs:
60 REM    - count of primes <= LIMIT
70 REM    - sum of primes <= LIMIT
80 REM    - maximum gap between consecutive primes in that range
90 REM    - last TAIL primes (in increasing order)
100 REM
110 REM  Notes:
120 REM    - Uses a boolean array IsPrime() for the sieve.
130 REM    - Avoids storing all primes by keeping only the last TAIL
140 REM      primes in a circular buffer TailPrime().
150 REM ================================================================

160 PRINT "Prime statistics (Sieve of Eratosthenes)"
170 PRINT

180 INPUT "Upper limit (>= 0) "; LIMIT
190 IF LIMIT < 0 THEN LIMIT = 0

200 INPUT "How many last primes to print (tail, >= 0) "; TAIL
210 IF TAIL < 0 THEN TAIL = 0

220 PRINT
230 PRINT "Building sieve up to "; LIMIT; " ..."
240 PRINT

250 REM ----- Allocate arrays -----
260 DIM IsPrime(LIMIT)
270 IF TAIL > 0 THEN DIM TailPrime(TAIL)

280 REM ----- Initialize primality flags -----
290 FOR I = 0 TO LIMIT
300   IsPrime(I) = 0
310 NEXT I
320 FOR I = 2 TO LIMIT
330   IsPrime(I) = 1
340 NEXT I

350 REM ----- Sieve of Eratosthenes -----
360 ROOT = INT(SQR(LIMIT))
370 FOR P = 2 TO ROOT
380   IF IsPrime(P) <> 0 THEN
390     M = P * P
400     WHILE M <= LIMIT
410       IsPrime(M) = 0
420       M = M + P
430     WEND
440   END IF
450 NEXT P

460 REM ----- Scan primes; compute statistics on the fly -----
470 COUNT = 0
480 SUM# = 0#
490 PREV = -1

500 MAXGAP = 0
510 GA = 0
520 GB = 0

530 IDX = 0   REM last written position in TailPrime()

540 FOR N = 2 TO LIMIT
550   IF IsPrime(N) <> 0 THEN
560     COUNT = COUNT + 1
570     SUM# = SUM# + N

580     IF PREV >= 0 THEN
590       GAP = N - PREV
600       IF GAP > MAXGAP THEN
610         MAXGAP = GAP
620         GA = PREV
630         GB = N
640       END IF
650     END IF
660     PREV = N

670     REM Keep last TAIL primes in a circular buffer
680     IF TAIL > 0 THEN
690       IDX = ((COUNT - 1) MOD TAIL) + 1
700       TailPrime(IDX) = N
710     END IF
720   END IF
730 NEXT N

740 REM ----- Report -----
750 PRINT "limit="; LIMIT
760 PRINT "count="; COUNT
770 PRINT "sum="; SUM#

780 IF COUNT < 2 THEN
790   PRINT "max_gap=0 (fewer than two primes)"
800 ELSE
810   PRINT "max_gap="; MAXGAP; " between "; GA; " and "; GB
820 END IF

830 REM ----- Print tail primes in increasing order -----
840 IF TAIL > 0 AND COUNT > 0 THEN
850   PRINT "tail:";
860
870   IF COUNT < TAIL THEN
880     REM All primes fit in the buffer in direct order.
890     FOR K = 1 TO COUNT
900       PRINT TailPrime(K);
910     NEXT K
920   ELSE
930     REM Oldest of the last TAIL primes is one step after IDX.
940     START = (IDX MOD TAIL) + 1
950     FOR K = 0 TO TAIL - 1
960       POS = ((START - 1 + K) MOD TAIL) + 1
970       PRINT TailPrime(POS);
980     NEXT K
990   END IF
1000
1010   PRINT
1020 END IF

1030 END
 
Same code in Python and Perl by a certain LLM imp.

The same non-subject says that this code "Computes all prime numbers up to an integer limit using the Sieve of Eratosthenes, then prints (1) how many primes exist up to that bound, (2) their sum, (3) the largest gap between consecutive primes in that range, and (4) the last few primes."

Personally, I find the Perl version much more readable.

Python:
#!/usr/bin/env python3
import argparse

def sieve(limit: int) -> list[int]:
    if limit < 2:
        return []
    is_prime = bytearray(b"\x01") * (limit + 1)
    is_prime[0:2] = b"\x00\x00"
    p = 2
    while p * p <= limit:
        if is_prime[p]:
            step = p
            start = p * p
            is_prime[start : limit + 1 : step] = b"\x00" * (((limit - start) // step) + 1)
        p += 1
    return [i for i in range(2, limit + 1) if is_prime[i]]

def main() -> None:
    ap = argparse.ArgumentParser(description="Compute primes up to a limit and print summary statistics.")
    ap.add_argument("--limit", type=int, default=100000, help="Upper bound (inclusive).")
    ap.add_argument("--tail", type=int, default=10, help="How many of the largest primes to print.")
    args = ap.parse_args()

    primes = sieve(args.limit)
    count = len(primes)
    total = sum(primes)
    max_gap = 0
    gap_pair = None

    for a, b in zip(primes, primes[1:]):
        g = b - a
        if g > max_gap:
            max_gap = g
            gap_pair = (a, b)

    print(f"limit={args.limit}")
    print(f"count={count}")
    print(f"sum={total}")
    if gap_pair:
        print(f"max_gap={max_gap} between {gap_pair[0]} and {gap_pair[1]}")
    else:
        print("max_gap=0 (fewer than two primes)")

    tail = primes[-args.tail:] if args.tail > 0 else []
    if tail:
        print("tail:", " ".join(map(str, tail)))

if __name__ == "__main__":
    main()

Perl:
#!/usr/bin/env perl
use strict;
use warnings;
use Getopt::Long;

sub sieve {
    my ($limit) = @_;
    return () if $limit < 2;

    my @is_prime = (0, 0, (1) x ($limit - 1));  # indices 0..$limit
    for (my $p = 2; $p * $p <= $limit; $p++) {
        next unless $is_prime[$p];
        for (my $m = $p * $p; $m <= $limit; $m += $p) {
            $is_prime[$m] = 0;
        }
    }
    my @primes;
    for my $i (2 .. $limit) {
        push @primes, $i if $is_prime[$i];
    }
    return @primes;
}

my $limit = 100000;
my $tail  = 10;
GetOptions(
    "limit=i" => \$limit,
    "tail=i"  => \$tail,
) or die "Usage: $0 [--limit N] [--tail K]\n";

my @primes = sieve($limit);
my $count = scalar @primes;

my $sum = 0;
$sum += $_ for @primes;

my $max_gap = 0;
my ($ga, $gb);
for (my $i = 0; $i + 1 < @primes; $i++) {
    my $g = $primes[$i + 1] - $primes[$i];
    if ($g > $max_gap) {
        $max_gap = $g;
        ($ga, $gb) = ($primes[$i], $primes[$i + 1]);
    }
}

print "limit=$limit\n";
print "count=$count\n";
print "sum=$sum\n";
if ($count >= 2) {
    print "max_gap=$max_gap between $ga and $gb\n";
} else {
    print "max_gap=0 (fewer than two primes)\n";
}

if ($tail > 0 && $count > 0) {
    my $start = $count - $tail;
    $start = 0 if $start < 0;
    print "tail: ";
    print join(" ", @primes[$start .. $count - 1]), "\n";
}

For me, Perl5 code usually goes to hell when I want named parameters to functions and reference or value comes in.
 
BTW, it's quite evident that BWBasic doesn't need the line numbers, but I left them because they give to the script a nice vintage BASIC touch.
 
I used to read some people saying bad things about Tcl, sometimes repeating some very old and wrong ideas.
Decided to give it a try.
Compared its speed against another candidate, Raku (Perl 6) and for my test case, Tcl single threaded was as fast as Raku multi-threaded.
Decided to take the plunge with Tcl and some years later, I can say that Tcl + Tk + Sqlite is a real productivity powerhouse.
I own my current job to the tools built with them.

Tcl has a low profile community, use old but the very best Usenet forums instead of proprietary Discord, uses IRC instead of other more modern but less freedom friendly resources.
 
Please note , there exists no "Best Language".
Yes, which is why most people with any programming competence are either sticking to specific projects in a given language or have a short list of languages for different uses as just about any language can be used for a given purpose, some are just better suited to it than others. Between, Bourne Shell scripting, perl5 and Java I can cover the vast majority of situations that I'm likely to need to write something that doesn't already exist. And, there are some rather nice interface options these days for writing quickie things for either running in a console or in X.

Personally, I try to moderate what I say about Python at work because there are students present that are being forced to learn it, but Python is not a friend of beginning programmers, it's barely even friend-shaped for more experienced ones. I wonder how many people give up after that initial programming class thinking they can't program because the colleges around here think that Python is a suitable beginner language when there are so many issues for beginners, things like semantic white space, the unhelpful error messages and the weird typing system going on under the hood where the students don't see it. It's not a bad language for some uses, but most of the things that it's good for use C libraries anyways and there's no inherent reason why they need to be for Python.

At least for the semantic whitespace aspect there are preprocessors out there that can allow you to ignore that nonsense and process your source into something that Python understands.

TLDR; on that second bit don't choose Python if you're a newb because you think it's for newbs, it's not, and if you do and get frustrated don't assume that it's because you can't learn to program, Python is just a terrible place to start learning.
 
Excerpts from the previous post, which is very enlightening and deserves the attention.

I try to moderate what I say about Python at work because there are students present that are being forced to learn it

Python is not a friend of beginning programmers, it's barely even friend-shaped for more experienced ones

there are so many issues for beginners, things like semantic white space

don't choose Python if you're a newb because you think it's for newbs, it's not
 
Back
Top