A file manager is a program that lets you interact with a file-system. A filesystem is the abstraction used by your OS to expose the data stored on your computer (in a hard drive, a virtual partition etc.) or any external devices (such as a memory stick). Most users will really only be familliar with large, graphical file managers such as windows file explorer or on linux, GNOME Files or Konqueror (more recently KDE dolphin). Personally I use a mixture of dolphin and a terminal file manager called lf.
The advantages of a graphical file manager are numerous; extended key support, tabs, dialogs for file transfers, automatic device mounting etc. However in this post, I'd like to explain why even users of dolphin (or the plethora of other such graphical file managers) could benefit from a textual interface from time to time 😁.
#Speed
lf is fast. It's insanely fast.
The actual startup time generally varies depending on the speed of the device you're current working directory is in, but there's very little latency from the file manager itself. In comparison dolphin can take anywhere from 2-10 seconds to startup for me.
Though startup time isn't the only metric in which lf
is fast. Moving across the
file system, inputting key commands, cutting and pasting files. Everything is
extremely responsive. Lets try jumping through a symlink to another device.
How about previewing a file and then opening the preview in my pager?
Like with vim, there's very little lag between user input and program output. As you grow accustomed to it and your hands start to remember your bindings, you become able to jump through your file system at blazing speed.
#Seperation of Concerns
The single best part about terminal file managers is that they're minimalist but extensible. Meaning out of the box, they generally don't come with very many builtin commands or operations, but give you the ability to extend and build on them. This lets you chain different programs together to improve your user experience.
#Fuzzy Jump
Lets try using fzf
to jump to this file in my blogs repository
There's a few cool concepts at play here.
fzf
is being spawned as a subprocess of mylf
client, howeverlf
lets me supersede control to it. All input is being redirected tofzf
and thelf
output is essentially hidden until the subprocess finishesfzf
is respecting my .gitignore file. I can't fuzzy jump to a file in my node_modules or vendor directory. I have a seperate command designed to let my fuzzy jump to all files, but the default one only lets me jump to project files.fzf
shows file previews as well. I'm sharing the same preview script betweenfzf
andlf
so there's less of an interface shock when using the command.
It's worth mentioning that none of this is built into lf
, you have to program them
yourself, meaning you can shape the experience you want.
#Bulkrename
This is the most valuable, most useful, most essential part of my setup. bulkrename
is a command I initially encountered in ranger. I missed it so much when I
moved to lf
that I created my own script to emulate it. It works by
opening a file list in the editor of your choice, and then runs a few different
commands depending on how you modify the file.
Let's say I have a bunch of video files with a prefix indicating where I got them
from, but I don't care about that so I'd like to remove it. In the old days I'd
probably have written a script (or a very long command line) to read each file and
then process them. With lf
I can do it in under a minute.
Here I've:
- selected all files with a
.mkv
extension, - ran the
bulkrename
command on them to open a file list, - removed the vendor prefix (
[HorribleSubs]
) from all files, - renamed the
-
seperator toEP
, - changed the resolution indicator (
[1080p]
to.1080p.
)
All in under a minute.
steps 1 and 2 were done in lf
, whereas the remaining steps where done in vim
. For
step 3 I used visual-block-mode to select and remove the prefix. The last two steps I
executed using a vim macro (a way to record and repeat keypresses) which
was required because of how each line had a different length.
What I wanted to show with this example was how efficiently I was able to go from
intention to goal. It took under a minute to batch process over 100 files. Why? The
seperation of concerns. lf
is a good file manager, all the file selection and file
system related operations were done in it. vim
is a good text editor, all the
modifying file names and user interaction was done from it.
Terminal file managers hook into the unix philosophy of do one thing and do it well exceptionally. My editor is good at editing text, so use it to rename and modify file names. My file manager is good at showing me and letting me select files, so let it do that. Each thing does what it does well and you get a highly efficient workflow.
#Grouping Files
Bulkrename isn't limited to simply renaming, my script exposes the commands for movement and deletion as simple shell functions, which the user can modify to do with as they will. Let's say I have a bunch of numbered folders and I'd like to group them into 10s.
Here I have a bunch of numbered directories and I've simply grouped them into a folder matching the 10s digit of the number. Admittedly I've relied on all the folders having a number in the same place and of the same width, but for more unstructured data you can always resort to a macro or even a subshell. Linux is extremely flexible in how it lets you approach problems like this.
#A Practical Application
Bulkrenaming itself is pretty practical, but I thought it'd be cool to end with a
demonstration of how I use lf
all the time.
Not to toot my own horn, but I'm an avid manga reader; I have a vast somewhat
oversized 😅 collection of manga in .cbz or .cbr format. Ocassionally I scrape
chapters from mangasites, or download digital releases, but at the end of the day I
like to read it on my phone. There are apps for reading .cbz or .cbr files, but
I've yet to encounter a better reader for iOS than adobe acrobat. So I've taken to
batch converting manga to PDFs and then sharing them to my phone. As a practical
example, let's demonstrate how I do that.
I have a script which reads in paths to image files and then lazily builds
a .pdf file from them. I had to rely on python and use an external dependency
because literally EVERY script or processor I encountered I really only tried
imagemagick and some other scripts I found online to do so ended up keeping the
entire PDF file in memory; which even for small volumes lead to my computer crashing.
My script uses pillow and a not very well documented feature of it that
lazily appends images to a PDF. The trade off is that it has to open the PDF file for
every image it writes, which for PDFs with 100s of images starts to slow down
immensely but I prefer this to crashing.
So here's what we're gonna do. We're gonna use lf
to select a few volumes we want
to read now, we'll find all images in each volume, make sure their ordered correctly
and then pass them to my script to turn them into a PDF, which we'll save with the
same name as the volume in a subdirectory and with a .pdf extension.
NOTE: for the sake of this demonstration I've truncated each volume down to just 10 images. In practice I generally do this with upwords of 100-200 images at once. However that would've taken too long.
So to summarise:
- I used
lf
to select the two volumes I want to convert. - I create an inline script to iterate for each selected volume.
- I found each file in each volume, sorted them and then passed them to
img2pdf
. - Then I finally trashed the original volume directory because it's no longer necessary.
NOTE: At the end I manually created the out directory and moved the .pdf into there. I could've done so in the script itself, but I'd have to parse out the volumes basename first, which seemed like too much of a hassle for this demo.
#Conclusions
To conclude there isn't much else to say, aside from
Terminal File Managers are Awesome!
If you spend a lot of time fussing around with files and collections, or navigating through a filesystem. It really helps to have an interface to that file system that's closely tied to your shell. I highly recommend looking through some of the different file managers out there. A good introductory one would have to be ranger. It's written in python and has a plugin system related to python modules. nnn is also a well liked file manager (although I've never been much attracted to it).
lf is the file manager I've been using in these examples. It has an unorthodox config format; I'd decribe it as a strange mix of vimlang and kakoune, but I'm quite fond of how simple it is to extend. Shell scripts are inherently designed to plug different programs together and being able to do that in your file manager is amazing.
To finish, here's a link to all the scripts I've used in this post and my lf
config file.