Aliases and Scripts
Posted on Mon 16 September 2024 in blog
Over the years I’ve developed (and stolen) a lot of shortcuts and scripts for accomplishing tasks quickly from the command line. I’ve written about them before; it is time now to go further and document all of the absolute best scripts in my possession.
Aliases
To use these aliases for yourself, copy and paste them into your
~/.bash_aliases
file (or ~/.zsh_aliases
if you use zsh instead of bash).
wec
Sometimes I download an image from the Internet but it arrives in the .webp
format, a newfangled image format that often needs to be converted before being
recognized as an image in other utilities (for example, if I’m uploading an
avatar for a web site or game). My bash alias wec
automatically converts all
webp files in a directory to png files. Requirements:
imagemagick,
fd-find, and the standard Unix tools
sed and
xargs.
alias wec='fd webp$ | sed "s/.webp$//" | xargs -n1 -I {} dwebp {}.webp -o {}.png' # webp convert
Example usage:
$ cd Downloads
$ ls
cool-avatar.webp # Yay, my file I downloaded is here, but it's a webp file
$ wec
Decoded cool-avatar.webp. Dimensions: 421 x 611 . Format: lossy. Now saving...
Saved file cool-avatar.png
$ ls
cool-avatar.webp cool-avatar.png
serg
sed
can be used as an entire local find-and-replace. I only really use this in
directories where the files are tracked in git / version control, because it can
be a bit risky, otherwise, to bulk change your files unless it’s trivial to
revert changes.
function serg {
sed -i -e "s/$1/$2/g" $(rg -l "$1")
}
Example usage: I use this a lot in software development, e.g. if I’ve decided to
rename a variable unload_s3_path
to s3_table_path
to reflect that “unload”
is no longer the only table-populating strategy:
serg unload_s3_path s3_table_path
today
My alias today
creates a directory called ~/today/
in my home folder if it
does not exist, and within it, creates a subfolder ~/today/2024-09-16/
if it
does not exist. Then it outputs the name, which (since I tend to run this from
emacs) allows me to jump straight into that new directory with g f
. I store
all kinds of things in there, typically just
org files with simple to-do lists and
other notes.
function today() {
TODAY_DIR="$HOME/today/"
DATE_DIR=$(date +'%Y-%m-%d')
if [ ! -d $TODAY_DIR$DATE_DIR ];
then
mkdir -p $TODAY_DIR$DATE_DIR
fi;
echo $TODAY_DIR$DATE_DIR
}
export today
Example usage:
$ today
/home/signmaker/today/2024-09-16
vi ~/today/2024-09-16/hotfix.txt
(I’m sorry if you’re the redditor or Mastodonian I stole this script from. I tried to find you in order to give credit but wasn’t able to.)
Scripts
When a task that I need automated is too complex to express as one or two lines
of bash, I store it in ~/mega/scripts/
, a directory that is synced across my
computers. Here’s all the information you need to adopt one of them (after
copying the script itself into a file in your own scripts directory):
- These scripts are accessible in any directory, just as if they were a
bash_alias, because the following line is always in my
~/.bashrc
(or~/.zshrc
if I were to use zsh):export PATH="$PATH:$HOME/mega/scripts"
- I also, when I add a new script to this directory, or install the directory
onto a new computer, need to run the following
chmod command to make each script
executable:
chmod +x ~/mega/scripts/*
- My scripts use Python, so Python needs to be installed.
age
Starting off simple - I frequently forget, or feel uncertainty, about my own age! But there is no need to be:
#!/usr/bin/python3
"""Output my current age."""
import datetime
years = datetime.datetime.now() - datetime.datetime(year=1987, month=4, day=26)
print(round(years.days / 365, 2))
Example usage:
$ age
37.42
reminders
Even simpler, this is just a list of things that I benefit greatly from being able to quickly remind myself:
- The incantations to make ripgrep omit certain parts of its typical output
- Date and datetime formatting syntax for Python
- The syntax to quickly print “foo=’bar’” in Python, given a variable
foo
containing the value"bar"
- The magic strings used for the tabulate library
- Commands to open a postgresql shell from its docker container
- Command to instantiate a pandas dataframe with a couple of rows of sample data
#!/usr/bin/env python3
"""I still always forget certain things."""
reminders = """
rg options: -o/--only-matching; -I no filename; -N no line number
strftime: %Y-%m-%d %H:%M:%S; or month words %B/%b; weekdays %A/%a
f-string tricks: f"{foo=}"; f"{num:.2f}"
tabulate kwargs: tablefmt=(default "simple", github", "markdown", "orgtbl", "plain", "rounded_grid")
sql shell: postgres (alias for docker exec -it postgres /bin/bash); then psql -U {username} -d {database}
dataframe: df = pd.DataFrame({"Name": ["John", "Alice", "Bob"], "Age": [25, 30, 35], "City": ["New York", "London", "Paris"]})
""".strip()
print(reminders)
sleeep
sleep is a frequently useful
command, but when invoking it from the shell (for example in order to run say
"Job's done"
when 3 minutes have elapsed), I find myself wondering “Are we
there yet?” My script sleeep
does the same thing as sleep
, except that it
prints a counter for how many seconds have elapsed.
#!/usr/bin/python3
"""Count down a user-specified number of seconds."""
import sys
import time
try:
to_sleep = int(sys.argv[1])
except (IndexError, TypeError):
print("usage: sleeep seconds")
sys.exit(1)
for second in range(to_sleep):
print(second, end="\r")
time.sleep(1)
print(to_sleep)
exc
This script converts back and forth between Excel’s column nomenclature (e.g. “A”, “B”, “C”, …, “Z”, “AA”, “AB”, …) and indexes in a Python list. It becomes useful when switching back and forth between Excel and Python, for example, when programming a script to generate a copy of a spreadsheet. When the list of columns becomes long enough, it’s very convenient to be able to quickly identify that the 33rd column is “AH”, or that column CAZ is column 2079.
#!/usr/bin/env python3
"""Convert from Excel column lettering to 0-indexes or back."""
import sys
def column_to_index(column):
"""Convert Excel column name to 0-indexed integer."""
index = 0
for char in column:
index = index * 26 + (ord(char) - ord("A") + 1)
return index - 1 # because it's 0-indexed
def index_to_column(index):
"""Convert 0-indexed integer to Excel column name."""
column = ""
while index >= 0:
column = chr(index % 26 + ord("A")) + column
index = index // 26 - 1
return column
arg = sys.argv[1]
if arg.isalpha(): # Check if the input is an alphabetical column name
print("Index", column_to_index(arg))
elif arg.isnumeric(): # Check if the input is a numeric index
print("Column", index_to_column(int(arg)))
Example usage:
$ exc 33
Column AH
$ exc CAZ
Index 2079