TIL: Show the application switcher on all screens

I have multiple monitors and I use the cmd + tab application switcher often. I find the current behavior of macOS pretty confusing. By default, it only shows the switcher on the most recently used screen. But that’s not the screen I’m looking at when switching to another application!

After getting confused a bunch of times, I found this setting which lets you show the switcher on all screens:

defaults write com.apple.dock appswitcher-all-displays -bool true
killall Dock # you need to restart the Dock for settings to take effect

Screenshot of two screens with the same App Switcher active on each

It’s wonderful.

TIL: Control less options globally with LESS

While researching interactive flags in less I learned about the LESS env var. This lets you set less’s startup flags globally. For example, if you always want ANSI color escape sequences to be interpreted (so you see colors instead of control characters), put LESS=-R in your shell config.

export LESS=-R
less request.log

Screenshot of HTTP request log with HTTP status codes in color.

export LESS=
less request.log

Screenshot of HTTP request log with HTTP status codes surrounded by control characters like ESC[33m.

TIL: less lets you toggle startup flags interactively

I love the less pager. You can use it to read, search, tail, and more. As with many versatile programs, however, the man page for less has a bazillion different options:

$ man less

NAME
    less - opposite of more

SYNOPSIS
    less [-[+]aABcCdeEfFgGiIJKLmMnNqQrRsSuUVwWX~]

There’s hardly a letter it doesn’t use!

Of these, my favorites are:

  • -S or --chop-long-lines. Truncate lines rather than wrapping them.
  • -N or --LINE-NUMBERS. Show line numbers at the start of each line.
  • -R or --RAW-CONTROL-CHARS. Show control characters vs. interpret them.

You can supply these as flags when starting less. But you often don’t start less directly; it’s set as your pager and then gets invoked when you run commands that produce lots of output, like man or git. No matter because you can type the startup flags while less is running to toggle their behavior!

If lines are wrapped and you want to truncate them, just type -S. You’ll see a message at bottom describing the change and then you press enter to accept. Want to see what line number something is on? Type -N, enter.

Screen recording of opening an HTTP request log with less, then toggling escape codes to color, toggling wrapped long lines to be truncated, then enabling line numbers

As an aside: the dominant pager that preceded less was more. Despite the names, less has more features. On macOS, more is now less (or more precisely, /usr/bin/more and /usr/bin/less are the same file):

ls -lih /usr/bin/more /usr/bin/less
1152921500312523552 -rwxr-xr-x  2 360K Nov 22  2025 /usr/bin/less
1152921500312523552 -rwxr-xr-x  2 360K Nov 22  2025 /usr/bin/more

Whether you get more’s impoverished capabilities or less’s expansive set is determined by the name you use to invoke it.

TIL: Mojibake

I learned a new word today: mojibake!

Some of my old blog posts have random gibberish in them like ñ or ’. I always assumed this was the result of some character encoding mismatch but I didn’t know exactly what was going on. While I was fixing this issue via find/replace technology, I did some reading to learn more.

The short version is a mismatch between UTF-8 and Latin-1 (ISO-8859-1) encodings. As an example, this is how ñ becomes ñ.

First, when I type ñ in my CMS it is represented in UTF-8:

>> "ñ".codepoints
=> [241]
>> "ñ".bytes
=> [195, 177]

In UTF-8, codepoints above 127 are represented with more than one byte. You can see here the codepoint 241 (U+00F1) corresponds to two bytes, 195 and 177.

Then, when these bytes get written to the DB, they are not converted from UTF-8 to Latin-1. We store [195, 177] but believe they are Latin-1. Later, we re-encode these bytes as UTF-8 to convert from not-actually-Latin-1:

bytes = "ñ".bytes               # => [195, 177]
latin1_str = bytes.pack("C*").force_encoding("ISO-8859-1")
puts latin1_str.encode("UTF-8") # => ñ

I was fixing these bugs in old posts and one AI result said, “Oh yeah, this is a classic mojibake problem.” My first reaction was, “I don’t know man–How ‘classic’ can it be if I’m hearing it for the first time after working with strings and encodings for years?” But then again, you have to learn everything sometime. Maybe it is classic!

Mojibake or 文字化け is a Japanese word for exactly this kind of garbled text. Before UTF-8, the dominant character encoding in Japan was Shift JIS, and this kind of character mangling was probably common when text interacted with systems that did not convert encodings properly.

The “moji” in mojibake (文字) means text and, yes, it’s the same moji found in emoji (絵文字)! I knew that emoji originated in Japan but I did not know that the name was actually Japanese. I assumed that emo was related to emotion since the first emoji were all faces showing different emotions. Nope! E (絵) means pictures, moji (文字) means text.

Now that UTF-8 is the dominant text encoding, I’m pretty confident you’ll see all the text here correctly and not as a “classic” mojibake issue.

TIL: Spotlight can do math and unit conversions

You can open macOS’s Spotlight with cmd + space. Then you can type in math like (4 + 23) * 92 and it will show you the answer. I’ve been using this feature for awhile but I just learned that it can do a lot more than I realized! This came up because I typed 2**256 and it gave me the answer. Interesting…what else can it do?

Screenshot of Spotlight answers to math like round(4723/125) and sin(pi/2), as well as unit conversions like 95F and 10 miles in feet. The answer to each query is selected in blue so it can be copy/pasted.

I couldn’t find a comprehensive list of supported features. This Stack Overflow answer has a long list; one other commenter says it’s everything the macOS calculator can do. All of these things work:

  • Exponents, written as any of 2**3, 3^2, or pow(2, 10)
  • Factorials, written as 5! or fact(7)
  • Trigonometry, functions like sin, cos, tan, and constants like pi.
  • Lots of other math. You can round(), pow(), abs(), sqrt(), ceil(), floor(), and more.

The absolutely best part is that it does unit conversions. Historically this is one of the things I have always typed into Google search. I’m sure I’m going to use this all the time now. Type 95F and it tells you that’s 35°C. Type 170 lbs and it says 77 kg. You can specify the output unit like 4 Tbsp in mL or 10 miles in feet (it does not, however, support unhinged unit conversion like “1 mile in furlongs”).

One really nice UX touch is that Spotlight automatically selects the answer, so you can easily copy it with cmd + C without dragging.

TIL: pkill to stop a process by name

Sometimes when I learn about a tool I think “wow, that would have been useful [when I had some problem in the past]”. That happened with pkill, which is a command you can use to stop a process accurately.

Many years ago I was slogging through debugging a Selenium test failure in a Rails application with my coworker, Ron. Every time we made a change we had to stop the server, restart it, and re-run the test suite. This had a bunch of steps so naturally we wrote a script to automate them. At the end of the script, we killed the Rails server by looking for the process using port 3000 with kill -9 $(lsof -t -i:3000).

  • lsof lists open files. In unix/linux, everything is a file including things like network connections (via sockets).
  • -t terse output–just the pid
  • -i:3000 process using port 3000

It worked! Until one run when, all of a sudden, my entire browser disappeared. It was unexpected, abrupt, and rude. We were using that browser! Ron and I were really baffled … until we realized that there were two processes using the port: the server and the browser (maybe with a keep alive connection?).

This is what the lsof output looks like when you look for processes using a port:

$ lsof -i:3000 -P

COMMAND  PID    TYPE  NODE  NAME
ruby3.2  42727  IPv6  TCP   *:3000                           (LISTEN)
ruby3.2  42727  IPv6  TCP   localhost:3000->localhost:57537  (ESTABLISHED)
Google   6439   IPv6  TCP   localhost:57537->localhost:3000  (ESTABLISHED)

Notice that process ID 42727 is using :3000 in the LISTEN state, while that same process and Chrome are both using it for a connection in the ESTABLISHED state. So we got unlucky on one run, grabbed the browser’s process ID, and unceremonously killed it. At the time, we worked around this by adding another flag, -sTCP:LISTEN. This filters to TCP sockets in the LISTEN state, so we’d always get the server process.

pkill would have been perfect for this! It stops processes by matching the process name. For example, pkill ruby would stop all running ruby processes. That’s a little aggressive if you only want to stop one process. With pkill -f you match the program arguments as well, like ruby bin/rails so pkill -9 -f rails would do it. (You could also argue that I should have the server process itself write its pid to a file to later stop it. You’re probably right!)

One thing I love is programs that have two modes to either (1) take action or (2) preview that action. Many systems expose this as a “dry run”. In the case of pkill, the dry-run equivalent is pgrep, which works the same way, but just outputs the pid instead of sending a kill signal.

pkill has a ton of other options so be sure to look at the tldr or man page.

TIL: cmd + shift + G to Go To Folder

GUIs are great! But I’m used to typing cd, and sometimes I prefer that to clicking around to get somewhere.

MacOS merges these worlds with cmd + shift + G. In the Finder it’s under GoGo to Folder.... This opens a dialog where you can type a path to navigate to. It supports tab completion, it understands that ~ is your home directory, and it shows recently used options that you can navigate with your arrow keys.

Screenshot of Go to Folder window with ~/code/ in the input box and a list of possible destinations below

It also works in the open/save dialog boxes! This is more hidden; as far as I know there is no menu that shows “Go To Folder” so you just have to know the cmd + shift + G shortcut.

Screenshot of Go to Folder being used with an open/save dialog box in the background

Now when I’m not navigating to the Desktop, Documents, or Downloads (which each have their own keyboard shortcuts), I often use cmd + shift + G to get there.

TIL: badssl.com lets you test bad certificates

While working on Slack’s unfurl previews I needed to test what happens when the fetcher cannot access a site. People put a lot of different URLs into Slack; some of them are going to be unfetchable for various reasons. Pointing the fetcher at a URL that doesn’t resolve, or one that results in a timeout, is straightforward, but I don’t know enough to set up various bad SSL/TLS scenarios. Surely one of them is going to have a bad config at some point.

That’s when I found https://badssl.com. It’s a project from some security folks that provides tons of misconfigured sites for exactly this purpose. Want to see what happens with an expired cert? Go to https://expired.badssl.com. How about a cert that’s been revoked? That’s https://revoked.badssl.com/.

For example, this is how curl behaves when the certificate doesn’t match the domain name:

$ curl https://wrong.host.badssl.com/
curl: (60) SSL: no alternative certificate subject name matches target host name 'wrong.host.badssl.com'
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

This is what it looks like when you navigate to a site where the certificate has expired:

Screenshot of Chrome showing a warning for expired.badssl.com that says "Your connection is not private" and the error code ERR_CERT_DATE_INVALID.

I love that badssl.com gives you a quick way to check these behaviors interactively. For example, curl https://tls-v1-1.badssl.com:1011 works fine; going to that URL in Chrome presents a warning (because TLS v1.1 is deprecated).

There are more than 70 subdomains in 13 categories so you can trigger mixed content warnings, HTTP form behaviors, HSTS, and more.

TIL: Find shared lines with comm

diff is a well-known tool to see what lines are different between files; comm is a less-known tool to see the common lines.

I found comm when I was looking for a way to identify lines that are shared (or not) between files. Specifically, I had two lists: one with all the APIs in my codebase, and another with all the tested APIs. From this I wanted to get a list of untested APIs.

As an aside, my go-to in this situation is to drop in a Ruby one-ish-liner:

ruby -e "puts (File.readlines('all') - File.readlines('tested'))"

In Ruby, Array.- (minus) returns a new array after removing the elements from the right-hand side. IMO, this is pretty nice. Ruby has a wide variety of methods for combining arrays (+ to merge, - for difference, & for intersection, | for union). The only caveat is that this is trickier if you haven’t written the lines to a file. That’s pretty common in pipelines and was, in fact, exactly the situation in which I found myself.

Let’s say we have these two lists: mammals.txt and pets.txt:

$ cat mammals.txt
cat
dog
lion
rabbit
whale
$ cat pets.txt
cat
dog
fish
rabbit
snake

We can compare the files with comm:

$ comm mammals.txt pets.txt
		cat
		dog
	fish
lion
		rabbit
	snake
whale

The first time I saw this output I was pretty confused. Is this working? It kind of looks like I just dumped all the lines with weird indentation? comm produces output in three columns:

  1. lines that are only in the first file
  2. lines that are only in the second file
  3. lines that are in both files

Here’s a labeled version:

$ comm mammals.txt pets.txt
just          | just       |
mammals.txt   | pets.txt   | both
--------------+------------+-------
              |            | cat
              |            | dog
              | fish       |
lion          |            |
              |            | rabbit
              | snake      |
whale         |            |

You can use -1 to hide the first column, -2 to hide the second column, and, yes, -3 to hide the third column. In this case, if you want just animals that are mammals and pets: comm -12 mammals.txt pets.txt:

$ comm -12 mammals.txt pets.txt
cat
dog
rabbit

If you want pets that aren’t mammals, that would be comm -13 mammals.txt pets.txt.

To get back to my original use case, if I want a list of untested APIs, you write:

comm -23 all_apis.txt tested_apis.txt

comm works with process substitution so you can also write:

comm -23 <(command to find all APIs) <(command to find tested APIs)

One caveat: the input lines need to be sorted, so you may need to add | sort.

TIL: Reorder columns, print the last with awk

awk is a whole programming language, but 90% of what I use it for is printing a subset of columns. This is pretty much covered by cut with two exceptions: re-ordering columns and printing the last column. Both cut and awk call columns “fields”.

Here’s some sample tab-separated data (formatted with column -t!):

FirstName  LastName  FavoriteColor  Pet
Elena      Kowalski  yellow         hamster
Marcus     Rivera    green          snake
Nadia      Ferreira  coral          rabbit
Yuki       Tanaka    pink           cat
Zara       Okonkwo   indigo         chinchilla

If you just want a list of favorite colors, you select the third field with cut -f3:

cat data.tsv | cut -f3
FavoriteColor
yellow
green
coral
pink
indigo

But if you want last name then first name, no dice. You can run cut -f2,1 but it will output them in the original order. For this I learned to use awk. You have to remember to specify the field separator with -F, then you put the program to run on each line in braces:

cat data.tsv | awk -F'\t' '{ print $2, $1 }'
LastName FirstName
Kowalski Elena
Rivera Marcus
Ferreira Nadia
Tanaka Yuki
Okonkwo Zara

If you want the last field in the input (in my case I was looking at log lines), you have two options: count the number of fields and use cut (no thanks, I’m too lazy) or use awk. The variable you want is $NF for “number of fields”. Since the fields are one-indexed, this will give you the last field.

cat data.tsv | awk -F'\t' '{ print $NF }'
Pet
hamster
snake
rabbit
cat
chinchilla

I usually have to look up -F'\t' even though I should probably remember “field separator” is -F.