Is Your Mental Model Of Bash Pipelines Wrong?

[Michael Lynch] encountered a strange situation. Why was compiling then running his program nearly 10x faster than just running the program by itself? [Michael] ran into this issue while benchmarking a programming project, pared it down to its essentials for repeatability and analysis, and discovered it highlighted an incorrect mental model of how bash pipelines worked.

Here’s the situation. The first thing [Michael]’s pared-down program does is start a timer. Then it simply reads and counts some bytes from stdin, then prints out how long it took for that to happen. When running the test program in the following way, it takes about 13 microseconds.

$ echo '00010203040506070809' | xxd -r -p | zig build run -Doptimize=ReleaseFast
bytes: 10
execution time: 13.549µs

When running the (already-compiled) program directly, execution time swells to 162 microseconds.

$ echo '00010203040506070809' | xxd -r -p | ./zig-out/bin/count-bytes
bytes: 10
execution time: 162.195µs

Again, the only difference between zig build run and ./zig-out/bin/count-bytes is that the first compiles the code, then immediately runs it. The second simply runs the compiled program. Continue reading “Is Your Mental Model Of Bash Pipelines Wrong?”

Using Local AI On The Command Line To Rename Images (And More)

We all have a folder full of images whose filenames resemble line noise. How about renaming those images with the help of a local LLM (large language model) executable on the command line? All that and more is showcased on [Justine Tunney]’s bash one-liners for LLMs, a showcase aimed at giving folks ideas and guidance on using a local (and private) LLM to do actual, useful work.

This is built out from the recent llamafile project, which turns LLMs into single-file executables. This not only makes them more portable and easier to distribute, but the executables are perfectly capable of being called from the command line and sending to standard output like any other UNIX tool. It’s simpler to version control the embedded LLM weights (and therefore their behavior) when it’s all part of the same file as well.

One such tool (the multi-modal LLaVA) is capable of interpreting image content. As an example, we can point it to a local image of the Jolly Wrencher logo using the following command:

llava-v1.5-7b-q4-main.llamafile --image logo.jpg --temp 0 -e -p '### User: The image has...\n### Assistant:'

Which produces the following response:

The image has a black background with a white skull and crossbones symbol.

With a different prompt (“What do you see?” instead of “The image has…”) the LLM even picks out the wrenches, but one can already see that the right pieces exist to do some useful work.

Check out [Justine]’s rename-pictures.sh script, which cleverly evaluates image filenames. If an image’s given filename already looks like readable English (also a job for a local LLM) the image is left alone. Otherwise, the picture is fed to an LLM whose output guides the generation of a new short and descriptive English filename in lowercase, with underscores for spaces.

What about the fact that LLM output isn’t entirely predictable? That’s easy to deal with. [Justine] suggests always calling these tools with the --temp 0 parameter. Setting the temperature to zero makes the model deterministic, ensuring that a same input always yields the same output.

There’s more neat examples on the Bash One-Liners for LLMs that demonstrate different ways to use a local LLM that lives in a single-file executable, so be sure to give it a look and see if you get any new ideas. After all, we have previously shown how automating tasks is almost always worth the time invested.

Suc Aims To Replace Slack In Five Lines Of Bash

The design philosophy of Unix is fairly straightforward. Software should do one thing as simply as possible, and do that one thing only. As a design principle this is sound advice even well outside of the realm of Unix, and indeed software in general, but that doesn’t stop modern software packages from being too large for their own good. So, if you’re tired of bloated chat programs like Slack or Mattermost with their millions of lines of code, you might instead favor something like Simple Unix Chat (suc).

The idea is that suc can perform almost all modern chat functions in only five lines of Bash, supporting rich-text chat, file sharing, access control, and encryption. These five lines, though, only perform the core function of suc — which is to write text to a file on the system. Indeed, suc makes liberal use of plenty of other Unix services which do not add to the line counts, such as the use of SSH to handle authentication. It also relies on some other common Unix system features to handle things like ownership and access for the text files that host the text for the chat.

As channels are simply text files, it makes writing bots or other tools exceptionally simple. You can also easily pipe the output of commands directly into suc with one-liners that can do things like dump the output of make into a specific channel if compilation fails.

While it’s not likely that everyone will ditch tools like Slack to switch to something like this, it’s still an impressive demonstration of what can be done when designing around the Unix philosophy and taking advantage of system tools that already exist rather than reinventing the wheel and re-programming all of those tools into the application. Practices like this might decrease development time and increase the ease of developing cross-platform applications but they often also produce a less than desirable user experience.

Linux Fu: Supercharge Bash History

Having a history of shell commands is a great idea. It is, of course, enormously handy when you have to run something repetitively or you make a simple mistake that needs correction. However, as I’ve mentioned in the past, bash history isn’t without its problems. For one thing, by default, you don’t get history in one window from typing in another window. If you use a terminal multiplexer or a GUI, you are very likely to have many shells open. You can make them share history, but that comes with its own baggage. If you think about it, we have super fast computers with tons of storage compared to the “old days,” yet shell history is pretty much the same as it has been for decades. But [Rcaloras] did think about it and created Bashhub, a history database for bash, zsh, and probably some other shells, too.

Command detail screen

You might think you don’t need anything more than what you have, and, of course, you don’t. However, Bashhub offers privately stored and encrypted history across machines. It also provides context about commands you’ve executed in the past. In other words, you can see the directory you were in, the exact time and date, the system you were on, and the last return code of the command.

Continue reading “Linux Fu: Supercharge Bash History”

Before You Sudo Rm -rf /, Take Some Precautions

Maintaining or administering a computer system remotely is a common enough task these days, but it’s also something that can go sideways on you quickly if you aren’t careful. How many of us are guilty of executing a command, having it fail, and only then realizing that we weren’t connected to the correct computer at all? [Callan] occasionally has this issue as well, but in at least one instance, he deleted all of the contents of the wrong server by mistake. To avoid that mistake again, he uses color codes in the command line in a fairly unique way.

The solution at first seems straightforward enough. Since the terminal he’s using allows for different colors to be displayed for the user and hostname on the bash prompt, different text and background colors are used for each server. The only problem with this is that his friends also have access to these servers, and one of them is red/green colorblind, which led to another near-catastrophic mix-up. To ensure no edge cases are missed, [Callan] built a script which runs on every new server he spins up which selects two random colors, checks that they contrast well with each other, don’t create problems for the colorblind, and then applies them to the bash prompt.

For a problem most of us have had at some point or another, it’s a fairly elegant solution that helps ensure we’re sending the right commands to the right computer. This adds a layer of automation to the process and, while some color combinations do look similar, there are enough to help out most of us in some way, especially since he has released the source code on his GitHub page. For other helpful server administration tips, we’d recommend the Linux-Fu article about deploying your own dynamic DNS.

Linux Fu: Gum Up Your Script

We often write quick bash scripts and judging by the comments, half of us use bash or a similar shell to pop out quick, useful scripts, and half of us think that’s an abomination, and you should only use bash for your command line and resort to something more like a traditional language to do anything else. If you’re in the former camp, you’re probably cursing your allegiance when you need to make your bash scripts more interactive.

Gum can help. It’s a utility that can handle your script input and output with a little flair while requiring almost no effort on your part.

The command looks simple, but it has twelve subcommands, each with myriad options. But you can break down the functions into a few simple categories. The input commands let you prompt for a line of input or a bunch of lines of input. You can also create a pick list or a yes/no type of prompt. There’s also a file picker and a filter, sort of like fzf.

Continue reading “Linux Fu: Gum Up Your Script”

Linux Fu: Bash Strings

If you are a traditional programmer, using bash for scripting may seem limiting sometimes, but for certain tasks, bash can be very productive. It turns out, some of the limits of bash are really limits of older shells and people code to that to be compatible. Still other perceived issues are because some of the advanced functions in bash are arcane or confusing.

Strings are a good example. You don’t think of bash as a string manipulation language, but it has many powerful ways to handle strings. In fact, it may have too many ways, since the functionality winds up in more than one place. Of course, you can also call out to programs, and sometimes it is just easier to make a call to an awk or Python script to do the heavy lifting.

But let’s stick with bash-isms for handling strings. Obviously, you can put a string in an environment variable and pull it back out. I am going to assume you know how string interpolation and quoting works. In other words, this should make sense:

echo "Your path is $PATH and the current directory is ${PWD}"

The Long and the Short

Suppose you want to know the length of a string. That’s a pretty basic string operation. In bash, you can write ${#var} to find the length of $var:


#/bin/bash
echo -n "Project Name? "
read PNAME
if (( ${#PNAME} > 16 ))
then
   echo Error: Project name longer than 16 characters
else
   echo ${PNAME} it is!
fi

Continue reading “Linux Fu: Bash Strings”