Published by bp99 on Sun Aug 11 20:50:04 2019

bp99

Korn Shell globbing

TL; DR

Remove all files but one in ksh using the following:

$ rm !(file)

Context

I was experimenting with dictfmt today. This utility generates DICT protocol compatible dictionary files. Here is some insight into what using it looked like:

$ <testdict.txt dictfmt --locale en_US.UTF-8 -j testdict >/dev/null
$ ls
testdict.dict  testdict.index  testdict.txt anothertest.txt

Problem

At a point like this I wanted to clean up my testing directory a little bit by removing everything but the source testdict.txt file.

Solutions

1. KISS

Granted, with 3–4 files, it would not have been horrible to just do

$ rm testdict.dict testdict.index anothertest.txt

or even

$ rm testdict.{dict,index} anothertest.txt

But I have been in situations such as this before (especially working with LaTeX)—I mean when I have to keep one file in a directory but delete everything else. You don't want to do this with more files.

2. KISS improved

Without thinking too much, you can just move the file into another directory, purge the files with a simple * glob and then move it back.

$ mv testdict.txt /tmp/
$ rm *
$ mv /tmp/testdict.txt .

This is actually quite a nice solution; you can even write a little function to do this for you:

rmbut()
{
        mv "$1" /tmp/
        rm *
        mv "/tmp/$1" .
}

3. Globbing

This is where I wanted to get. Since I am not bound to using something as barebones as /bin/sh, I can take advantage of the extended globbing feature of more advanced shells.

I have been using fish (the Friendly Interactive SHell) before. A long time ago I also tried zsh. However, since I switched to OpenBSD, I got to like ksh.

In ksh, such an operation can easily be done using an extended glob. Observe:

$ rm !(testdict.txt)

This is one kind of many extended globs. I haven't experimented much with the others.