I love using UNIX’s/Linux’s command line (aka shell, aka terminal) because it has excellent options for customizations and extensions. There are dozens of standard coreutils as well as hundreds (thousands?) of extra CLI utilities. Some tools can increase your productivity significantly once you get used to them; one of those is
fzf — a fuzzy finder, which allows you to pick an item/a set of items from a list quickly. It has a number of useful commands and key bindings out of the box and of course you can write your own! That’s what I wanted to do to start using it more frequently and help with frequent actions.
My use case is to pick a booted iOS Simulator for a command. Most of the time I use one simulator, so a typical command for me would be
xcrun simctl uninstall booted org.example.app to uninstall an application from the booted simulator. However that command fails when I have 2+ open simulators, in which case I need to provide a UDID of the simulator I want to target. Do you easily remember the UDIDs of the simulators that you use often? I don’t, so the tiny task here is to get the UDID of a simulator by its name. That’s where
fzf comes in. (Granted, in this case I’m unlikely to have dozens of simulators open at the same time to justify using a fuzzy finder, but I needed to start somewhere.)
Note: I’m using zsh as the main shell, so the commands here are tested only in that shell.
Which simulators are booted?
First, we need to get a list of currently booted iOS Simulators in order to pipe them to
fzf. A simple way would be:
1 2 3
rg here, but the regular
fgrep would work just fine too. The output isn’t very script-friendly; no fear, we can massage the output into what we’d like more:
1 2 3
BTW I learned about this trick about a single
sed command to filter and modify data from a
git man page (don’t remember which one). This command is too dependent on the output format of
simctl, and there is a more script-friendly way, via json:
1 2 3
Where would we be without
jq?! This command iterates over all
devices of all device types and prints tab-separated
udid of those that are
"Booted". The ‘tab’ character is used to here to be able to separate those two fields easily.
Now we can compose a pipeline that will let us select a booted simulator by name (or UDID if you so wish) and prints its UDID. It looks like this:
1 2 3 4 5 6 7
fzf’s prompt, I can type
ai and it will leave only the “iPad Air”. Then I press
Enter, and the result is:
Attaching a hotkey
Now I would like to get the picker when I’m typing a command, e.g. when I press
Ctrl-g Ctrl-s (the mnemonic is “Get Simulator”):
To do that, I put this into my
1 2 3 4 5 6 7
fzf-ios-sim is a function (and a zsh completion widget) that will capture the selected UDID and append it to the string typed so far. I don’t fully understand the details of ZLE here, so I tweaked it reading the references until it started to work. The references are:
1 2 3
This is a simple widget and a great place to start. There are a number of possible improvements here: for example, if I cancel
fzf, the widget will print
'', but should print nothing; or it would be nice to be able to switch between a list of booted simulators and a list of all available simulators.
ps. Initially I wanted to show only the simulators’ names, but return the UDID of the selected one. I couldn’t figure out how to do that with
fzf, and in reality displaying the UDID is not an issue. What I wanted is something like this Haskell code, filtering by name but returning UDID: