Bash
Amending PATH
(something arcane that exists in “system variables” on windows that I had always been a bit afraid of) allows you to call scripts in a particular directory from anywhere on your system. All the programs/functionaly that normally work in the terminal (cd
, ls
, mkdir
, python
etc.) have to be placed somewhere that the terminal can find them. Otherwise you’re just shouting into the void and computer says no, I don’t know what that is.
On MacOS and Linux (and probably windows too), the PATH
variable is actually incredibly simple, and can be easily and safely edited. In this example, I edit the PATH
to add my crypto-prices
directory, so when I call the bash function crypto.sh
, the shell knows what I’m talking about.
Step 1. Editing the PATH Variable
Edit the PATH
in ~/.zshrc
:
open ~/.zshrc
Add the line export PATH="PATH:$HOME/Documents/Code/scratch/cryptoprices
somewhere in .zshrc
. This defines a new PATH
, but to stop the previous PATH
from being overwritten you must prepend the path to your new directory with PATH
. Alternatively you can add your new directory to the end of a long PATH
string, deliminated by :
, with $PATH
at the end, e.g.:
export PATH="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/homebrew/bin:/opt/homebrew/opt/python@3.12/libexec/bin:$HOME/code/scratch/crypto-prices:$PATH"
which lists in order all the directories the shell will look for programs/commands entered into the terminal.
Bash and Python Files of Interest
I have three scripts and one venv/
directory in $HOME/code/scratch/crypto-prices
directory of interest here ($HOME
expands to the user’s home directory):
- crypto.sh - bash script that activates the venv, checks the script arguments, determines which python file to run and runs it with user arguments
- simple.py - python script that prints the current crypto prices for BTC, ETH, LINK, DOT, ADA using the Binance API
- complete.py - does the same as simple.py but with added functionality for calculating wallet amounts and printing the all-time-highs
- venv/ - directory storing the virtual environment in which the python library
requests
is installed.
The full, heavily commented, crypto.sh script is as follows:
#!/bin/bash
# The first line, the "shebang," tells the system which interpreter to use for the script.
# Set the path to the virtual environment directory.
# "VENV_PATH" is a variable storing the full path to the virtual environment.
VENV_PATH="$HOME/code/scratch/crypto-prices/venv"
# Check if the virtual environment exists by testing if the "activate" script is present.
# "-f" checks if a file exists and is a regular file (not a directory).
if [ -f "$VENV_PATH/bin/activate" ]; then
# "source" runs the file in the current shell, activating the virtual environment
source "$VENV_PATH/bin/activate"
else
# If the file doesn't exist, print an error message and exit the script with a status of 1 (indicating failure).
echo "Error: Virtual environment not found at $VENV_PATH"
exit 1
fi
# Check if at least one argument is provided when running the script.
# "$#" represents the number of arguments passed to the script. "-lt 1" means "less than 1".
if [ "$#" -lt 1 ]; then
# If no arguments are provided, print usage instructions to help the user.
# "$0" refers to the name of the script itself (e.g., ./crypto.sh).
echo "Usage: $0 <script_name> [script_args]"
echo "Available scripts: simple, complete"
exit 1
fi
# Store the first argument (the script name) in the variable "SCRIPT_NAME".
# "$1" is the first positional argument passed to the script.
SCRIPT_NAME=$1
# "shift" removes the first argument from the list of positional arguments ($1), shifting all others down.
shift
# Here "$@" (all arguments as a single space-separated string) will only additional script arguments (if any).
# Store the remaining arguments (after removing the first) in the variable "SCRIPT_ARGS".
SCRIPT_ARGS="$@"
# Use a "case" statement to map the script name provided by the user to the actual Python script file.
# The "case" construct is like a switch statement in other languages.
case $SCRIPT_NAME in
# If the user specifies "simple" as the script name, set "SCRIPT_PATH" to the corresponding file path.
simple)
SCRIPT_PATH="$HOME/code/scratch/crypto-prices/simple.py"
;;
# If the user specifies "complete," set "SCRIPT_PATH" to a different file path.
complete)
SCRIPT_PATH="$HOME/code/scratch/crypto-prices/complete.py"
;;
# If the script name doesn't match any of the predefined options, handle it as an error.
*)
# Print an error message and remind the user of the available options.
echo "Unknown script name: $SCRIPT_NAME"
echo "Available scripts: simple, complete"
exit 1
;;
esac
# Run the selected Python script using the Python interpreter from the virtual environment.
# "$SCRIPT_PATH" is the full path to the Python script determined earlier.
# "$SCRIPT_ARGS" contains any additional arguments passed by the user.
python "$SCRIPT_PATH" $SCRIPT_ARGS
# Deactivate the virtual environment to restore the shell's environment to its previous state.
deactivate
I can now run the simple
and complete
scripts globally:
$ crypto.sh complete -ath
--- All-Time Highs ---
Symbol ATH Current Price Change from ATH (%)
----------------------------------------------------------
BTC $108353.00 $104199.99 -3.83%
ETH $4868.00 $3272.49 -32.78%
LINK $53.00 $23.71 -55.26%
DOT $55.09 $6.92 -87.44%
ADA $3.10 $1.07 -65.62%