The terminal rabbithole
What would macOS power-users like myself do without the terminal? When I'm on my computer, perhaps 60% of my time is spent entirely in the terminal. You want to program? Use neovim in the terminal. You want to check the weather? Curl an API in the terminal. You want to convert an image to png? Use ffmpeg command in the terminal. You want to find a file? Use fzf in the terminal... Once I had understood the power of the terminal (and learned touch-typing), it was hard for me to use a GUI again. Whipping up efficient solutions to all my problems with the keyboard is not only quick but it's a lot of fun.
One of the things that make my workflow in the terminal possible is bash scripting - or actually, it's the main tool I utilize. And today I want to showcase some different scripts that I use every day.
If you want to browse through my development config on your own you are free to visit my dotfiles repo.
Bash: aliases
Before we head into the more advanced scripts I want to show off some simpler aliases that I use daily. Starting with the humble ls command.
# ls default
alias ls='ls -pAGoh -D "%d-%m-%Y %H:%M" '
It's a pretty normal alias for power-users to write, and here are what all the flags do:
- -p : suffix every dir with a slash
- -A : show hidden files (except for "." and ".."(parent) folder)
- -G : colorised input
- -o : list in long format without group id
- -h : use unit suffixes for file size (B, MB, GB etc.)
- -D : format date
As you can tell, that's a lot of things I'm doing all at once! It would certainly be a pain to type all this out every time I want to use the ls command.
But now... If you're a mac user, you can probably relate when I say that all the .DS_Store files that clog up our git repositories is a pain in the neck. But I've built a nice alias for this.
# recursively delete all .DS_Store files in current folder
alias ds='find . -name ".DS_Store" -type f -delete'
These kinds of commands that delete files in your system you need to be careful with though. When using a GUI file-browser you often get a little confirmation box to fill out before deleting - or if you regret the deletion, you've got the trashbin. In the terminal the concept of a trashbin is not there. This is really powerful but also quite risky. With great power comes great responsibility.
# define word
define() {
curl dict.org/d:$@
}
Here's a cool one! Ever need to get a definition for a word? Since I do a lot of writing in the terminal, this is certainly warranted every once in a while. When in doubt, curl!
Bash: scripts
Scripts is where the terminal can truly become a tool that outperforms a GUI. Without scripts and command pipelines the world would be a terrible place!
First thing I want to show you is my script for taking notes:
n() {
local name="$*"
local today
today=$(date +"%Y-%m-%d")
local dir="$HOME/notes"
# if no arg given, default to "note"
if [ -z "$name" ]; then
name="note"
fi
# format arg
name=$(echo "$name" | xargs | tr -s ' ' '-' | sed 's/-$//' | tr '[:upper:]' '[:lower:]')
local file="$dir/${name}_${today}.md"
mkdir -p "$dir"
# create empty file if it doesn't exist
[ -f "$file" ] || touch "$file"
nvim "$file"
}
This script is pretty self-explanatory, but in short, it takes the name of your new note as an argument, appends the current date to it, and creates a new file in the ~/notes/ folder as well as launching the new file in neovim. I use this script for reminders, shopping lists, todo lists and whatever else.
Now, these two following scripts are indispensable to me. These function as my replacement for searching files using a GUI application such as Raycast.
# local search from current directory
unalias s 2>/dev/null
s() {
local target
target=$(fd --type f --type d --hidden | fzf --preview='[[ -d {} ]] && exa -al --color=always {} || bat --style=numbers --color=always {}') || return
if [[ -d $target ]]; then
cd "$target"
elif [[ -f $target ]]; then
nvim "$target"
fi
}
# global search from home directory
unalias ss 2>/dev/null
ss() {
local target
target=$(fd --type f --type d --hidden . ~ | fzf --preview='[[ -d {} ]] && exa -al --color=always {} || bat --style=numbers --color=always {}') || return
if [[ -d $target ]]; then
cd "$target"
elif [[ -f $target ]]; then
nvim "$target"
fi
}
Again, pretty self-explanatory. But I'm using fzf to look for a file from either the home dir (ss) or the current dir (s) - and all this with file previews through the use of the bat command, and if the target is a file it launches directly in neovim, else I get cd'd into the directory. These could probably be improved by using MIME types or something like that, so that I can launch external applications, but for now I am satisfied with this!
Here is one last script I want to showcase! This is my devicon picker. I do like nerdfonts (this websites main font is Maple Mono for example) for its devicons. And similar to my "s" and "ss" commands, this also uses fzf to browse through a pre-defined collection of icons - when an icon is selected, it gets moved to my clipboard.
#!/usr/bin/env bash
lang="
bash
html
c
javascript
rust
lua
haskell
csharp
cpp
python
java
ruby
go
"
git="
git
github
gitadd
gitbranch
gitdiff
gitignore
gitmodify
gitdelete
gitrename
gitrepo
gitunmerged
gituntracked
gitunstaged
gitstaged
gitconflict
"
os="
applemac
linux
voidlinux
archlinux
windows
android
"
apps="
neovim
vim
emacs
github
gitlab
firefox
steam
terminal
"
arrows="
arrow-right
arrow-up
arrow-down
arrow-left
arrow-right
arrow-left
arrow-up
arrow-down
"
files="
folder
folder-open
file-doc
file
file-copy
dir-copy
file-image
file-video
"
sys="
disk
search
clipboard
user
"
web="
download
rss
cloud
database
inbox
"
other="
file-outline
flask
code
time-clock
openhand
rocket
pen
config
brush
brush
brush-x
brush
roller
paintcan
"
ui="
check
cross
warning
tick
cross
help
info
alert
"
unsorted="
file-pdf
arrow-down
arrow-up
link
shuffle
message
image-refresh
loop-refresh
loop-refresh
power
cart
record
record
view-eye
expand
view-eye
redo
calendar
search
multiple-monitors
monitor
gear
home
globe
mail
music-headphones
music
note
camera
image
film
volume
microphone
battery
wifi
database
clock
clock-filled
dot
users
link
user
gamepad
bar-chart
line-chart
pie-chart
circle
cross
question
info
delta
epsilon
phi
plus
minus
exclamation
alert
key
toggleoff
toggleon
gift
document
new document
lock
mail
bookmark
target
warning
redo
calendar
pen
magnet
"
devicons="
$unsorted
$os
$ui
$git
$web
$lang
$apps
$files
$arrows
"
selected=$(printf "%s\n" "$devicons" \
| fzf --prompt="devicon > " --height=40% --reverse) || exit 0
icon_char=$(printf "%s" "$selected" | awk '{print $1}')
printf "%s" "$icon_char" | pbcopy
printf "%s" "$icon_char"
This is all for now though - I hope this was relatively interesting to read!