Linux: List running services
Just came across this quick command to show running services.
systemctl list-units --type=service --state=running
Tags:
Just came across this quick command to show running services.
systemctl list-units --type=service --state=running
Tags:
It's a common practice to split a string on a delimiter like a comma or semi-colon. If your input data contains the delimiter in quotes you need to respect that and not split there. I wrote a simple function to handle 99% of the use cases for splitting in this manner.
quote_split('foo, bar, baz'); # ('foo', 'bar', 'baz')
quote_split("foo, 'bar, baz'"); # ('foo', 'bar, baz')
# Split a string on commas, but respect single and double quotes with commas
sub quote_split {
my ($str, $separator) = @_;
$separator //= ",";
if (!length($separator)) {
die("quote_split separator cannot be empty\n");
}
my $separator_re = quotemeta($separator);
my @items;
while ($str =~ /\G\s*(?:
"((?:\\.|[^"\\])*)" # Double-quoted
| '((?:\\.|[^'\\])*)' # Single-quoted
| ((?:(?!$separator_re)[\s\S])+) # Unquoted
)\s*(?:$separator_re|\z)/gcx) {
my $item = $1 // $2 // $3;
push(@items, $item);
}
return @items;
}
Tags:
I need very basic YAML parsing in Perl, mostly for reading configuration files. There aren't any great options in Perl core, and I only need a subset of YAML (basic scalars, arrays, and hashes), so I worked up a simple copy/pasteable function.
my $x = yaml_parse($yaml_str);
This implementation supports: nesting, scalars, arrays, and hashes, but is missing null / ~, booleans, and complex quotes.
sub yaml_parse {
return {} unless defined $_[0] && length $_[0];
my %data; my $root = \%data; my @st = ([-1, \$root]);
for my $line (split /\n/, $_[0]) {
$line =~ s/\r$//;
next if $line =~ /^\s*(?:$|---\s*$|#)/;
if ($line =~ /^(\s*)-\s*(.*)$/) {
my ($n, $v) = (length($1), $2);
pop @st while $n < $st[-1][0]; my $cur = ${$st[-1][1]};
die "yaml_parse: array without parent: $line" if @st == 1;
$cur = ${$st[-1][1]} = [] if ref $cur eq 'HASH' && !%$cur;
die "yaml_parse: mixed array/hash" if ref $cur ne 'ARRAY';
$v =~ s/^\s+|\s+$//g; $v =~ s/^(['"])(.*)\1$/$2/s;
$v += 0 if $v =~ /^-?\d+(?:\.\d+)?$/; if ($v =~ /^([\w\-\.\/]+):\s*$/) {
push(@$cur, my $el = {$1 => {}}); push(@st, [$n + 2, \$el->{$1}]); next; }
push(@$cur, $v);
} elsif ($line =~ /^(\s*)([\w\-\.\/]+)\s*:\s*(.*)$/) {
my ($n, $key, $v) = (length($1), $2, $3);
pop @st while $n <= $st[-1][0]; my $cur = ${$st[-1][1]};
die "yaml_parse: '$key' under array" if ref $cur eq 'ARRAY';
$v =~ s/\s+$//; $v =~ s/^\s+//; $v =~ s/^(['"])(.*)\1$/$2/s;
if ($v =~ /^\[(.*)\]$/) {
my @a = grep { length } map { s/^\s+|\s+$//gr =~ s/^(['"])(.*)\1$/$2/sr } split /,/, $1;
for (@a) { $_ += 0 if /^-?\d+(?:\.\d+)?$/ } $v = \@a;
} else { $v += 0 if $v =~ /^-?\d+(?:\.\d+)?$/; }
if (ref $v or length $v) { $cur->{$key} = $v }
else { $cur->{$key} = {}; push(@st, [$n, \$cur->{$key}]) }
} else { warn "yaml_parse: ignoring: $line\n" }
} return \%data;
}
YAML::XS is definitely the best Perl YAML parser, but it can be overkill if all you need is simple parsing.
Update: I wrote some unit tests to go along with this.
Tags:I ported my Sluz templating engine from PHP to JavaScript. It's now possible to run a full Sluz installation entirely in-browser. As a proof-of-concept I ported the Sluz Sandbox to use the JS version of library. Now you can test and validate Sluz code 100% in-browser.
Tags:AI models like Claude Opus and ChatGPT 5.6 are called "frontier" (i.e. top of the line). There are several fully open source frontier level AI models that are available to download for free. I ran the specs on what it would take to run a frontier level model.
For inference of a frontier model (400B-1T+ params):
- Minimum (4-bit quantized): ~200-500GB VRAM -> 4-8x H100 80GB GPUs
- FP16/half precision: ~800GB-2TB VRAM -> 10-32x H100 80GB GPUs
- System RAM: 512GB+
- Interconnect: NVLink or InfiniBand between GPUs
- Storage: Several hundred GB for model weights For training: 10,000-100,000+ GPU-hours on H100-class hardware, multi-million dollar cluster, weeks of continuous run time. No single consumer GPU can run a frontier model - even an RTX 4090 (24GB) is about 10-30x short of VRAM needed for even a heavily quantized frontier model.
If you just want to host a "good" AI model it requires 8x GPUs with 80GB of VRAM each.
It's about $300k to get in the door for a SINGLE server to run AI you can ask questions
Tags:Another day, another PRNG ported to Perl. Today is romuduojr from romu-random.org. Pretty simple 64bit PRNG.
Tags:I have a small Perl script that defines a handful of functions. Perl allows you to make a library that doubles as a script when called directly. Using caller() you can determine if your script was loaded via a require() call, or called directly. This allows you to export functions if called as a library, but run code if called directly via: perl my_lib.pl.
# my_lib.pl
if (!caller()) {
say greet("Scott");
}
sub greet {
my $name = shift();
return "Hello $name";
}
1; # Required if you load as a library
Use a require() call to load the module and get access to the greet() function.
# main.pl
require("/path/my_lib.pl");
say greet("Foo");
Tags:
I have a Git repository with a primary branch that I maintain actively. I also have a separate feature branch that I'd like to keep in sync with the main branch, and alert if there are any conflicts immediately. Using Git hooks you can script automatically pulling each new commit from the primary branch to the feature branch.
Create a .git/hooks/post-commit file and put these contents in it:
#!/bin/sh
SRC="main"
DST="feature"
branch=$(git branch --show-current)
if [ "$branch" = "$SRC" ]; then
commit=$(git rev-parse HEAD)
git checkout $DST &&
git cherry-pick "$commit" &&
git checkout main
fi
If there are conflicts, Git errors out immediately and leaves you on the feature branch to manually resolve the conflict.
Tags:I have two directories with (mostly) the same content that I want to keep in sync. Specifically I want to make sure that the newest version of each file is synced to the other directory. This allows me to update a file on either side, and that version will propagate to the other. You can do this with a bi-directional rsync command:
rsync --update -av /dir/a/ /dir/b/
rsync --update -av /dir/b/ /dir/a/
Using --update tells rsync to skip files on the receiving side that are newer. If you sync a -> b and then b -> a you end up with both locations having the newest copy of each file.
ULID's are an interesting way to generate globally unique identifiers. Here is a quickie Perl implementation to generate ULIDs. This implementation does not include the intra-millisecond monotonic increment however. If that feature is important to you consider checking out a more full-featured implementation like ULID::Tiny.
for (1 .. 5) {
say(ulid());
}
sub ulid {
my $ts = $_[0] || time() * 1000;
my $bytes = substr(pack("Q>", $ts), 2, 6);
# Append 10 random bytes
for (0 .. 9) { $bytes .= chr(int(rand(256))); }
# base32 encoding
my $bits = unpack("B*", $bytes);
my $pad = (5 - (length($bits) % 5)) % 5;
$bits .= '0' x $pad;
# Chars to use for base32
my @CROCKFORD_CHARS = split(//, '0123456789ABCDEFGHJKMNPQRSTVWXYZ');
my $result = '';
for (my $i = 0; $i < length($bits); $i += 5) {
my $chunk = substr($bits, $i, 5);
my $index = 0;
for my $bit (split //, $chunk) {
$index = ($index << 1) | $bit;
}
$result .= $CROCKFORD_CHARS[$index];
}
return $result;
}
See also: UUIDv7
Tags:Perl allows "inline" code written in other languages. This is useful because you can have native C functions interact with your Perl code. By placing your C code in the __DATA__ section of your Perl script you get clean separation between the two languages.
Note: Inline::C does not understand uint64_t in function definitions, so anything that interacts with Perl needs to use UV instead. Internally C functions can use and interact with uint64_t variables just fine.
use strict;
use warnings;
use v5.16;
use Inline 'C';
##############################################
seed_splitmix64(time());
for (1 .. 5) {
say splitmix64();
}
##############################################
__DATA__
__C__
uint64_t x = 123456789;
void seed_splitmix64(UV seed) {
x = seed;
}
UV splitmix64() {
uint64_t z = (x += 0x9e3779b97f4a7c15);
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
return z ^ (z >> 31);
}
This will compile the C code into a shared object in the _Inline directory in whichever directory you instantiated your Perl script. Code is only compiled once (and where there are changes), so your script performance will be very high.
I've been investigating JSON vs YAML vs TOML for various applications. After testing many variations I ended up writing a simple tool to compare all three live.
Tags:To display a message when a user logs into your server, add the following to ~/.bashrc:
# If it's an interactive terminal show the banner
if [[ $- == *i* ]]; then
echo "Welcome to the monitoring server"
echo "Configuration is stored in /etc/myapp"
fi
This runs only for interactive sessions. Non-interactive connections such as SFTP and SCP remain unaffected, which prevents automated processes from breaking.
See also: The text_color project.
Tags:The more I learn about YAML, the more I like it. JSON is great as a machine readable format, but it sucks at being human readable. Want to add an element, better make sure you have all the commas and curly braces in the exact right place or the whole thing will be unusable. YAML on the other hand is designed to be human readable and modifiable. It's a very simple key/value system using indentation to represent layers.
PHP has a PECL module with good YAML support. There are also pure PHP versions if you're unable to install PECL modules. Symfony provides one, and so does Spyc. I prefer the latter because it's a single file and very easy to install.
On the Perl side there is YAML::XS, YAML::PP, and many others.
Parsing YAML is very easy in just about every language I can find. If you have a complex data structure that you need humans to interact with use YAML please.
Here is a great breakdown of when to use YAML vs JSON:
| Use Case | Recommended | Why |
|---|---|---|
| API request/response | JSON | Universal support, strict parsing |
| Configuration files | YAML | Comments, readability |
| Browser/JavaScript | JSON | Native parsing |
| Kubernetes/Docker | YAML | Industry standard |
| Data interchange | JSON | Unambiguous, fast |
| Human-edited files | YAML | Less punctuation |
YAML spec differences.
Tags: