Files
davideisinger.com/static/archive/evanhahn-com-6hstph.txt
David Eisinger 0899b91eb2 Add links
2025-11-06 00:11:21 -05:00

419 lines
20 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Scripts I wrote that I use all the time
by [1]Evan Hahn
, posted Oct 22, 2025
In my [2]decade-plus of maintaining my dotfiles, Ive written a lot of little
shell scripts. Heres a big list of my personal favorites.
Clipboard
[3]copy and [4]pasta are simple wrappers around system clipboard managers, like
pbcopy on macOS and xclip on Linux. I use these all the time.
# High level examples
run_some_command | copy
pasta > file_from_my_clipboard.txt
# Copy a file's contents
copy < file.txt
# Open a file path from your clipboard
vim "$(pasta)"
# Decode some base64 from the clipboard
pasta | base64 --decode
[5]pastas prints the current state of your clipboard to stdout, and then
whenever the clipboard changes, it prints the new version. I use this once a
week or so.
# High level example
pastas > everything_i_copied.txt
# Download every link I copy to my clipboard
pastas | wget -i -
[6]cpwd copies the current directory to the clipboard. Basically pwd | copy. I
often use this when Im in a directory and I want use that directory in another
terminal tab; I copy it in one tab and cd to it in another. I use this once a
day or so.
File management
[7]mkcd foo makes a directory and cds inside. Its basically mkdir foo && cd
foo. I use this all the time—almost every time I make a directory, I want to go
in there.
[8]tempe changes to a temporary directory. Its basically cd "$(mktemp -d)". I
use this all the time to hop into a sandbox directory. It saves me from having
to manually clean up my work. A couple of common examples:
# Download a file and extract it
tempe
wget 'https://example.com/big_file.tar.xz'
tar -xf big_file.tar.xz
# ...do something with the file...
# Write a quick throwaway script to try something out
tempe
vim foo.py
python3 foo.py
[9]trash a.txt b.png moves a.txt and b.png to the trash. Supports macOS and
Linux. I use this every day. I definitely run it more than rm, and it saves me
from accidentally deleting files.
[10]mksh makes it quick to create shell scripts. mksh foo.sh creates foo.sh,
makes it executable with chmod u+x, adds some nice Bash prefixes, and opens it
with my editor (Vim in my case). I use this every few days. Many of the scripts
in this post were made with this helper!
Internet
[11]serveit starts a static file server on localhost:8000 in the current
directory. Its basically python3 -m http.server 8000 but handles cases where
Python isnt installed, falling back to other programs. I use this a few times
a week. Probably less useful if youre not a web developer.
[12]getsong uses yt-dlp to download songs, often from YouTube or SoundCloud, in
the highest available quality. For example, getsong https://www.youtube.com/
watch?v=dQw4w9WgXcQ downloads that video as a song. I use this a few times a
week&mldr;typically to grab video game soundtracks&mldr;
[13]getpod similarly uses yt-dlp to download something for a podcast player.
There are a lot of videos that Id rather listen to like a podcast. I use this
a few times a month.
[14]getsubs downloads the English subtitles for a video. (Theres some
fanciness to look for “official” subtitles, falling back to auto-generated
subtitles.) Sometimes I read the subtitles manually, sometimes I run getsubs
https://video.example/foo | ollama run llama3.2 "Summarize this", sometimes I
just want it as a backup of a video I dont want to save on my computer. I use
this every few days.
[15]wifi off, wifi on, and wifi toggle are useful for controlling my systems
wifi. wifi toggle is the one I use most often, when Im having network trouble.
I use this about once a month.
[16]url "$my_url" parses a URL into its parts. I use this about once a month to
pull data out of a URL, often because I dont want to click a nasty tracking
link.
url 'https://evil.example/track-user-link?url=https%3A%2F%2Furl-i-want-to-visit.example&track=06f8582a-91e6-4c9c-bf8e-516884584aba#cookie=123'
# original: https://evil.example/track-user-link?url=https%3A%2F%2Furl-i-want-to-visit.example&track=06f8582a-91e6-4c9c-bf8e-516884584aba#cookie=123
# protocol: https
# hostname: evil.example
# path: /track-user-link
# query: url=https%3A%2F%2Furl-i-want-to-visit.example&track=06f8582a-91e6-4c9c-bf8e-516884584aba
# - url https://url-i-want-to-visit.example
# - track 06f8582a-91e6-4c9c-bf8e-516884584aba
# hash: cookie=123
Text processing
[17]line 10 prints line 10 from stdin. For example, cat some_big_file | line 10
prints line 10 of a file. This feels like one of those things that should be
built in, like head and tail. I use this about once a month.
[18]scratch opens a temporary Vim buffer. Its basically an alias for $EDITOR $
(mktemp). I use this about once a day for quick text manipulation tasks, or to
take a little throwaway note.
[19]straightquote converts “smart quotes” to “straight quotes” (sometimes
called “dumb quotes”). I dont care much about these in general, but they
sometimes weasel their way into code Im working on. It can also make the file
size smaller, which is occasionally useful. I use this at least once a week.
[20]markdownquote adds > before every line. I use it in Vim a lot; I select a
region and then run :'<,'>!markdownquote to quote the selection. I use this
about once a week.
[21]length foo returns 3. (I should probably just use wc -c.)
[22]jsonformat takes JSON at stdin and pretty-prints it to stdout. I use this a
few times a year.
[23]uppered and [24]lowered convert strings to upper and lowercase. For
example, echo foo | uppered returns FOO. I use these about once a week.
[25]nato bar returns Bravo Alfa Romeo. I use this most often when talking to
customer service and need to read out a long alphanumeric string, which has
only happened a couple of times in my whole life. But its sometimes useful!
[26]u+ 2025 returns ñ, LATIN SMALL LETTER N WITH TILDE. A quick way to do a
lookup of a Unicode string. I dont use this one that often&mldr;probably about
once a month.
[27]snippets foo cats ~/.config/evanhahn-snippets/foo. I use snippet arrow for
→, snippet recruiter for a quick “not interested” response to job recruiters,
snippet lorem to print a “Lorem ipsum” block, and a few others. I probably use
one or two of these a week.
REPL launchers
Inspired by Rubys built-in irb REPL, Ive made:
• [28]iclj to start a Clojure REPL
• [29]ijs to start a Deno REPL (or a Node REPL when Deno is missing)
• [30]iphp to start a PHP REPL
• [31]ipy to start a Python REPL
• [32]isql to start a SQLite shell (an alias for sqlite3 :memory:)
Dates and times
[33]hoy prints the current date in ISO format, like 2020-04-20. I use this all
the time because I like to prefix files with the current date.
[34]timer 10m starts a timer for 10 minutes, then (1) plays an audible ring
sound (2) sends an OS notification (see notify below). I often use bb timer 5m
to start a 5 minute timer in the background (see bb below). I use this almost
every day as a useful way to keep on track of time.
[35]rn prints the current time and date using date and cal. I probably use it
once a week. It prints something like this:
4:20PM on Wednesday, October 22, 2025
September 2025
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
Audio and video and pictures
[36]ocr my_image.png extracts text from an image and prints it to stdout. It
only works on macOS, unfortunately, but I want to fix that. (I wrote [37]a post
about this script.)
[38]boop (an alias, not a shell script) makes a happy sound if the previous
command succeeded and a sad sound otherwise. I do things like run_the_tests ;
boop which will tell me, audibly, whether the tests succeed. Its also helpful
for long-running commands, because you get a little alert when theyre done. I
use this all the time.
[39]sfx foo basically just plays ~/.config/evanhahn-sfx/foo.ogg. Used in boop
and timer above.
[40]tunes uses mpv to play audio from a file. I use this all the time, running
tunes --shuffle ~/music.
[41]pix uses mpv to show a picture. I use this a few times a week to look at
photos.
[42]radio is a little wrapper around some of my favorite internet radio
stations. radio lofi and radio salsa are two of my favorites. I use this a few
times a month.
[43]speak reads from stdin, removes all Markdown formatting, and pipes it to a
text-to-speech system (say on macOS and espeak-ng on Linux). [44]I like using
text-to-speech when I cant proofread out loud. I use this a few times a month.
[45]shrinkvid is an ffmpeg wrapper that compresses a video a bit. I use this
about once a month.
[46]removeexif removes EXIF data from JPEGs. I dont use this much, in part
because it doesnt remove EXIF data from other file formats like PNGs&mldr;but
I keep it around because I hope to expand this one day.
[47]tuivid is one I almost never use, but you can use it to watch videos in the
terminal. Its cursed and I love it, even if I never use it.
Process management
[48]each is my answer to xargs and find ... -exec, which I find hard to use.
For example, ls | each 'du -h {}' runs du -h on every file in a directory. I
use this infrequently but I always mess up xargs so this is a nice alternative.
[49]running foo is like ps aux | grep foo but much easier (for me) to read—just
the PID (highlighted in purple) and the command.
[50]murder foo or murder 1234 is a wrapper around kill that sends kill -15
$PID, waits a little, then sends kill -2, waits and sends kill -1, waits before
finally sending kill -9. If I want a program to stop, I want to ask it nicely
before getting more aggressive. I use this a few times a month.
[51]waitfor $PID waits for a PID to exit before continuing. It also keeps the
system from going to sleep. I use this about once a month to do things like:
# I want to start something only after another process finishes
waitfor 1234 ; something_else
# I started a long-running process and want to know when it's done
waitfor 1234 ; notify 'process 1234 is done'
[52]bb my_command is like my_command & but it really really runs it in the
background. Youll never hear from that program again. Its useful when you
want to start a daemon or long-running process you truly dont care about. I
use bb ollama serve and bb timer 5m most often. I use this about once a day.
[53]prettypath prints $PATH but with newlines separating entries, which makes
it much easier to read. I use this pretty rarely—mostly just when Im debugging
a $PATH issue, which is unusual—but Im glad I have it when I do.
[54]tryna my_command runs my_command until it succeeds. [55]trynafail
my_command runs my_command until it fails. I dont use this much, but its
useful for various things. tryna wget ... will keep trying to download
something. trynafail npm test will stop once my tests start failing.
Quick references
[56]emoji is my emoji lookup helper. For example, emoji cool prints the
following:
😛
😒
😎
🪭
🆒
[57]httpstatus prints all HTTP statuses. httpstatus 204 prints 204 No Content.
As a web developer, I use this a few times a month, instead of looking it up
online.
[58]alphabet just prints the English alphabet in upper and lowercase. I use
this surprisingly often (probably about once a month). It literally just prints
this:
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
System management
[59]theme 0 changes my whole system to dark mode. theme 1 changes it to light
mode. It doesnt just change the OS theme—it also changes my Vim, Tmux, and
terminal themes. I use this at least once a day.
[60]sleepybear puts my system to sleep, and works on macOS and Linux. I use
this a few times a week.
[61]ds-destroy recursively deletes all .DS_Store files in a directory. I hate
that macOS clutters directories with these files! I dont use this often, but
Im glad I have it when I need it.
Grab bag
[62]catbin foo is basically cat "$(which foo)". Useful for seeing the source
code of a file in your path (used it for writing up this post, for example!). I
use this a few times a month.
[63]notify sends an OS notification. Its used in several of my other scripts
(see above). I also do something like this about once a month:
run_some_long_running_process ; notify 'all done'
[64]uuid prints a v4 UUID. I use this about once a month.
What about your scripts?
These are just scripts I use a lot. I hope some of them are useful to you!
If you liked this post, you might like [65]“Why alias is my last resort for
aliases” and [66]“A decade of dotfiles”.
Oh, and [67]contact me if you have any scripts you think Id like.
[68][logo_white]
• [69]About me
• [70]Contact
• [71]Projects
• [72]Guides
• [73]Blog
• [74]RSS
• [75]Newsletter
• [76]Mastodon
Unless noted otherwise, content is licensed under the [77]Creative Commons
Attribution-NonCommercial License and code under the [78]Unlicense. Logo by
[79]Lulu Tang. Profile photo by [80]Ali Boschert-Downs.
References:
[1] https://evanhahn.com/
[2] https://evanhahn.com/a-decade-of-dotfiles/
[3] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/copy
[4] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/pasta
[5] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/pastas
[6] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/cpwd
[7] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/zsh/.config/zsh/aliases.zsh#L38-L41
[8] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/zsh/.config/zsh/aliases.zsh#L43-L51
[9] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/trash
[10] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/mksh
[11] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/serveit
[12] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/getsong
[13] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/getpod
[14] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/getsubs
[15] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/wifi
[16] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/url
[17] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/line
[18] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/scratch
[19] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/straightquote
[20] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/markdownquote
[21] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/length
[22] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/jsonformat
[23] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/uppered
[24] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/lowered
[25] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/nato
[26] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/u+
[27] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/snippets
[28] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/iclj
[29] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/ijs
[30] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/iphp
[31] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/ipy
[32] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/isql
[33] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/hoy
[34] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/timer
[35] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/rn
[36] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/ocr
[37] https://evanhahn.com/mac-ocr-script/
[38] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/zsh/.config/zsh/aliases.zsh#L53-L61
[39] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/sfx
[40] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/tunes
[41] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/pix
[42] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/radio
[43] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/speak
[44] https://evanhahn.com/use-text-to-speech-if-you-cant-proofread-aloud/
[45] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/shrinkvid
[46] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/removeexif
[47] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/tuivid
[48] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/each
[49] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/running
[50] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/murder
[51] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/waitfor
[52] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/bb
[53] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/prettypath
[54] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/tryna
[55] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/trynafail
[56] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/emoji
[57] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/httpstatus
[58] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/alphabet
[59] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/theme
[60] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/sleepybear
[61] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/ds-destroy
[62] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/catbin
[63] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/notify
[64] https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d949d346a4a73ccee2a99351aed285b/home/bin/bin/uuid
[65] https://evanhahn.com/why-alias-is-my-last-resort-for-aliases/
[66] https://evanhahn.com/a-decade-of-dotfiles/
[67] https://evanhahn.com/contact/
[68] https://evanhahn.com/
[69] https://evanhahn.com/
[70] https://evanhahn.com/contact/
[71] https://evanhahn.com/projects/
[72] https://evanhahn.com/guides/
[73] https://evanhahn.com/blog/
[74] https://evanhahn.com/blog/index.xml
[75] https://buttondown.com/evanhahn
[76] https://bigshoulders.city/@EvanHahn
[77] https://creativecommons.org/licenses/by-nc/4.0/
[78] https://unlicense.org/
[79] http://luluspice.com/
[80] https://www.instagram.com/boschertdowns/