Skip to content
January 19, 2020 / gus3

A more expressive Bash prompt


Bash provides some interesting built-in specifiers for the prompt strings PS1. Some of them are static, like ‘\a’ for ‘alert’ (Ctrl-G, the bell, beep, or visible flash), or ‘\n’ or \r’ for newline or carriage return. Some specifiers are set during Bash’s startup, like ‘\h’ for the hostname, or ‘\u’ for the username; these don’t change during any particular shell session.

Some are more dynamic, like ‘\t’ for the current time (in 24-hour format) or ‘\w’ for the current working directory. From one command to the next, these are allowed to change. In fact, in the case of ‘\t’ or ‘\T’, they definitely will change.


19 years ago, I was distro-hopping, and discovered Gentoo. Its focus, then and now, has always been “make it shine!”. The visible stuff strives to be clean; the running code is intended to run fast (but still correctly). And it ran well enough for me, albeit with an occasional high CPU load to rebuild stuff, until it finally became too fragile and cracked during a failed install of the latest libffi build.

That aside, the first thing I noticed, at my first login, was Gentoo’s multicolored shell prompt. It gave a visible indicator of being a regular user (green) or having EUID 0, the root user (red). It was another example of color being used to indicate context, kind of like syntax highlighting in a text editor, but showing privileges to the user. A red prompt meant basically, “Caution! You can wreck this system, and I’ll let you,” while a green prompt says, “go ahead, you can only screw up your own stuff.” It’s kind of a broad interpretation, but that’s how I understood it at the time. If you’d like to explore the possibilities of a programmable Bash prompt, look here for some great examples.

So there are two things to understand about this post:

  1. For the last 8 years, my parents and I have used only Slackware Linux. Not to slight other Linux distros, but Slackware is the system I truly understand. And Slackware keeps things as “plain vanilla” as possible, so naturally the Bash command prompts in Slackware are just nice, but basic:




    No colors, nothing beyond the basic Bash prompt capabilities in any regular CLI terminal.
  1. In the past few years, my programming habits have distilled into “the language required by the assignment, then Bash if possible, finally C.” As a scripting language, Bash is enormously flexible, to the point that it can re-define its own behavior interactively. This is the same spirit of programming as GNU Emacs and the Xerox Alto.

What do I want in my prompt? Well, I’d like to see the result of the last thing I did, or tried to do. It’s no problem to show the exit status in PS1; you can embed ‘\?’ in the PS1 shell variable. But I want more power over it. MORE POWER! (evil laugh) Specifically:

I want the exit status in color. If it’s 0, that means the thing I typed finished successfully, so I want it in green (think “The Fifth Element”). If it didn’t work out, for any reason, I want to show it in red.

And another thing: if I can make the exit status colorful, I can make the user’s current info (name@host:pwd$) bold in case the EUID is root. Just as a nice touch.

The basic format is now something like this:

\? \u@\h:\w\$

but I want to colorize it, every time it appears. This means using Bash’s PROMPT_COMMAND variable to build PS1.

Read more…
June 11, 2019 / gus3

Let’s look at priorities

This isn’t about the operating system concept of scheduling priorities. It’s about getting real stuff done. Read more…

April 24, 2018 / gus3

Scripting an Animation

I remember watching the science programs of the 1980’s, such as Nova, National Geographic, and Cosmos. Their occasional computer animations, bringing to life some dry concept of mathematics or physics, were an endless source of awe. Partly, it was jealousy that someone had the equipment to make the animations real; also, some individual had the imagination to lay out what such an explanation should look like.

Fast-forward 30-some years, and I have the tools, the hardware and software, to do basic animations. But in typical Unix fashion, it’s up to me to put them together, to get them to work the way I want. Add to that the KISS principle, and it’s a simple matter of shell scripting!

Read more…

January 22, 2017 / gus3

Hello Debugger!

Sometimes, we get ideas we wish we’d thought of sooner. A few nights ago, I got this one: break to the debugger from the source code.

I’m a huge fan of GDB and DDD, but for anything beyond basic breakpoints, I’ve found myself wading through too much user documentation. What if I want a consistent conditional breakpoint, even if I add or remove earlier code? Never mind setting an initial breakpoint, then adding a data-dependent watchpoint… already, the terminology is getting thick. There has to be a better way.

Read more…

April 21, 2016 / gus3

In Real, Visual Terms

“If a 6600 used paper tape instead of core memory, it would use up tape at about 30 miles/second.” — Grishman, Assembly Language Programming

As legend has it, Grace Hopper (the original designer of COBOL) would hold up a length of wire, and ask her first-year students how long it was. It was just under 1 ft. (30.48cm) long. Most of her students answered with the visual length that they saw, and their answers were factually correct, but useless for the purpose of her class. The answer she wanted was “one nanosecond,” that is, the distance of the signal from one end of the wire to the other. On the lowest level, things happen in nanoseconds. (In silicon wafers, the design involves picosecond-timing considerations.)

But even in a nanosecond system, the physical design sometimes slows things down to microseconds or even milliseconds. The stored-program (Harvard) paradigm could be like this, with the executable instructions stored on some tangible medium like paper tape, while the executable’s data resided in fast-access, electronic storage.

And now, the world mostly uses the shared (von Neumann) paradigm, where the executable and the data may be stored in the same silicon wafer. Memory management can provide an architectural barrier between them, but 1’s and 0’s ultimately are just 1’s and 0’s. (But take a look at the postscript below.)

Let’s look back on that. 1’s and 0’s, but on punched tape.

Read more…

January 5, 2016 / gus3

An Open Letter to Mark Zuckerberg

“Don’t date the nerd…” Wait, you really said that to our nation’s female students?

That’s rich coming from you, Mr. Married-Three-Years-and-Counting. It’s a good thing for you Priscilla doesn’t think like that.

“Don’t date the nerd”? Thank heavens Chuck Lorre and Bill Prady have already decided that’s bad advice. Otherwise, a major plotline of our #1 TV comedy wouldn’t exist. Yet Kaley Cuoco, Mayim Biyalik, and Melissa Rauch bring their performances to show just how wrong-minded you are. Judging from the ratings, I’d say it’s a fair assessment that millions of their viewers agree: it’s OK to date the nerd. It’s even OK to marry the nerd.

(I can already hear lots of people responding, “it’s only a TV show!” I answer that with, “Of course. But the best comedy is grounded in reality.”)

Then again, would you advise our male students not to date nerds? No way; you’d be a stereotypical sexist pig to say something like that. So why is it OK to give our female students the same advice? Reverse sexism is still sexism.

Oh, but context matters, right? Not in this case. You made a blanket statement, to the effect that intimate relationships where one person who doesn’t work in STEM fields should avoid dating someone else who does work in STEM. Because, clearly (at least in your eyes) the one who doesn’t work in STEM is trying to find a sugar daddy (or sugar mama).

And that wasn’t even the case you were responding to. The girl’s grandmother was advising her to look for a provider, for her and their children. The grandmother may have been mis-guided about a “potential” provider, but she understands one crucial point: someone must bring the food, clothing, and shelter for the family.

But why should any of us take relationship advice from you? Because you founded Facebook? That isn’t a qualification. Because you run a massively popular website and can broadcast such advice to millions (even through third-party news outlets)? That doesn’t automatically make it good advice. Our relationships, on any level, are not for you to judge. In this case, your so-called “advice” is worthy only of contempt. And so, in reponse I say:

Piss off, you sexist hypocrite.

October 6, 2015 / gus3

A Little Diversion


The XtraScreenHacks screensaver collection for X11 has an interesting, if unusual, clock: the Berlin Clock, or “berlinuhr.” Based on the Set Theory Clock, it has four counting rows: five hours, single hours, five minutes, and single minutes, plus a single flashing second indicator on top.

As an independent study, I wanted to create a text-based version of the Berlin Clock, to learn a little ncurses programming, plus the ability to handle a terminal window resize. Read more…

January 12, 2015 / gus3

Getting a Time Without NTP

One of the drawbacks of a Raspberry Pi is its lack of an on-board clock. After a reboot, its clock is set to midnight, New Year’s Day, 1970 UTC, the beginning of the Unix epoch, and then the kernel boots. However, it is possible to get the current time early in the boot process, with one condition: an NFS root filesystem.

Read more…

August 11, 2014 / gus3

Intel Finally Slims Down

I know it’s been, oh, over a year since my last post. It’s been kind of like the Olympic gold medalist’s let-down: what do I do now? I’ve done a lot of tinkering, and “what happens if I do this?” kind of stuff, but nothing really big.

But this afternoon, I read about Intel’s new 14-nanometer process for making a CPU, giving 52-nm interconnects. Now, given that the covalent diameter of silicon is 222 picometers, a 52-nm interconnect would be:

52000 / 222 = 234 silicon atoms wide.

The mind boggles.

August 9, 2013 / gus3

Accessing the Raspberry Pi’s 1MHz timer, via kernel driver


As it turns out, my previous effort was, shall we say, somewhat off-base. Being a member of the “kmem” group, or running a SUID-root program, isn’t enough to access /dev/mem; the program capability CAP_SYS_RAWIO must also be present.
Read more…

July 1, 2013 / gus3

ARM VFP Vector Programming, Part 3: Source

Here are the source code and Make files for the two examples discussed in Part 2.

Read more…

June 27, 2013 / gus3

ARM VFP Vector Programming, Part 2: Examples

In Part 1, I explained the design philosophy of vector calculations using the ARM Vector Floating Point system. This article will demonstrate the actual practice of using vectors in the ARM VFP.
Read more…

June 25, 2013 / gus3

ARM VFP Vector Programming, Part 1: Introduction

The ARM VFP co-processor is most commonly used for individual floating-point computations, in the so-called “scalar mode.” In Flynn’s taxonomy, this is known as SISD, or “single instruction, single destination.” This design philosophy is the basic form for most low-level assembly most high-level compilers. In cases where different data sources are treated differently, for whatever reason, SISD is the norm.

However, when a block of identical operations are carried out on a sequence of data points, then it is possible to fetch several of the source data, and perform the operations on them all at once. This may be something as simple as adding the values of two arrays and storing the results into a third array, which may be part of a sophisticated analysis on a digital image. A close examination of the processing can show where Single Instruction, Multiple Destination (SIMD) design can boost a program’s performance.

Read more…

May 21, 2013 / gus3

Accessing the Raspberry Pi’s 1MHz timer

A fixed-rate timer is not part of the ARM specification, but most ARM-based SoC’s have such a timer. The Raspberry Pi is no exception. However, reading its timer in Linux takes a Unix hacker’s understanding.

Read more…

May 11, 2013 / gus3

When was that? Examining syslog timestamps

One convenient Linux kernel feature is an uptime stamp in each kernel log entry. This stamp is independent of the clock time, so small or large jumps in the clock have no bearing on the reported time for each entry.

Normally, the log files in /var/log/ will include a human-readable local time stamp before the log entry, but these files are readable only by the root user. Another possibility is that the logs are routed to another system for storage. This practice would also include restricting “dmesg” to the root user; the following won’t be useful in this case.

Read more…

March 18, 2013 / gus3

Tired of su-ing

One axiom of computing is to script commonly-used command sequences, akin to C’s functions, Pascal’s procedures, and Ada’s subprograms. But what if the command sequence involves “su” for elevated privileges? I found an idiom that Works For Me.

This example will pull pages from the swap space back into RAM:


case `id -u` in
    # The task is accomplished in the 0 case,
    # where we know we have root privileges.
    0) /sbin/swapoff -a
       /sbin/swapon -a
    # Everyone else gets to provide a password:
    *) exec /bin/su -c "`which $0`" - ;;

Anything requiring elevated privileges, or even simply someone else’s privileges, can be scripted this way. I have the above script in ~/bin/unswap. I have three other scripts in the same directory, called “slow”, “normal”, and “fast”, which set the CPU frequency governor to powersave, ondemand, or performance.

The one caveat is to hard-code the paths to the root-executed programs (which you already do in scripts, right?). You don’t want to execute a non-standard “swapon” that isn’t where you expect it to be.

(If someone would like to contribute an example using “sudo” instead of “su” it would be greatly appreciated.)

November 20, 2012 / gus3

HOWTO: Rebuild Glibc on Slackware ARM 14.0 for the Raspberry Pi

I run Slackware ARM on my Raspberry Pi. I’ve been a longtime fan of Slackware, which caters to my inner control-freak. However, since Slackware ARM (formerly ARMedSlack) is designed to run on a variety of ARM-based systems, and an ARM-based system is typically a System-on-Chip, this means that Slackware ARM is built for maximum compatibility… and minimum optimization. For example, not all ARM CPU’s have on-board floating-point capability. By assuming no floating-point capability, Slackware ARM can run on a wider range of ARM-based systems. However, this can reduce performance significantly.

This guide will explain how to rebuild core glibc libraries to use the greater capability of the Raspberry Pi’s on-board ARM 1176JZF-S CPU. The process is not terribly involved, but using NFS for the build space took 8-1/2 hours, even with the CPU overclocked to 900 MHz.

Read more…

November 20, 2012 / gus3

Comparing the x87 and ARM VFP


The first generation of x86 processors, the 8086 and 8088, had support for synchronous asymmetric multiprocessing. Synchronous, in that the main processor could wait for a READY/#BUSY or ERR signal from the coprocessor; and asymmetric, because the coprocessor’s instructions were completely different from the main processor’s. The coprocessor could not address memory, but had to wait for the main processor to decode an instruction’s addressing mode and then “open a window” into RAM for the coprocessor. The coprocessor could then read from or write to the data lines as required. For this reason, coprocessor instructions are always followed by at least one byte (ModR/M, in Intel terminology) indicating the addressing mode of the instruction. Coprocessor instructions operating on internal state only, with no memory access, could be carried out in parallel with main processor instructions, and the addressing mode byte indicates no memory access.

The coprocessor most often connected to the 8086 was the 8087 floating-point math unit. Later generations saw the 80x87 unit integrated with the main processor, at first by moving the chip logic onto the same wafer, but still using the same x86/x87 interconnect. With the Pentium series, the x87 was fully integrated into the superscalar design. The “coprocessor instruction space” became the “x87 instruction space.”

The ARM architecture has always had support for operations on up to 16 coprocessors. However, some operations now handled by coprocessors have not always been. For example, memory management is now handled by coprocessor 15, but the BBC Micro had the MEMC memory controller chip. The MEMC was managed by asserting values on the address bus, that is, reading or writing a particular location. If the address bits 25-17 contained 11011x111 in binary, then the MEMC interpreted the overall address as a re-configuration command for itself. (Interesting note: The binary sequence 11011 in the high bits is also how the 80x86 denotes a coprocessor instruction.)

Looking specifically at floating-point coprocessors, the x87 uses an extended precision (10 bytes) internally; handles logarithmic and trigonometric functions on-chip; and was strongly stack-based, though no longer so. The ARM vector floating-point (VFP) unit on the Raspberry Pi uses 4 or 8 bytes internally, does not support logarithms or trig functions in hardware, and supports the 3-register paradigm common to ARM (two source operands, and a third destination).

Let’s take a look at adding two floating-point values.
Read more…

October 2, 2012 / gus3

C-ing a Flashing Light

In my previous article, I showed how combining two instructions into one can speed up a very small countdown loop. In this article, I’ll demonstrate how a single non-optimizing compiler option can have an even greater impact on performance.

Read more…

September 14, 2012 / gus3

Immature Optimization

How much difference can a single instruction make? On the Raspberry Pi, it can make a difference of 14%, demonstrable without any expensive digital testing equipment.

Read more…