Browse Source

added service manager and tutorials

main
deicidus 1 year ago
parent
commit
00f310906c
  1. 24
      spells/cantrips/cd
  2. 22
      spells/cantrips/fathom-height
  3. 18
      spells/cantrips/fathom-width
  4. 2
      spells/cantrips/menu
  5. 59
      spells/install-service-template
  6. 38
      spells/is-service-installed
  7. 44
      spells/menu/bitcoin/bitcoin-menu
  8. 64
      spells/menu/bitcoin/bitcoin-status
  9. 28
      spells/menu/bitcoin/bitcoin.service
  10. 78
      spells/menu/bitcoin/change-bitcoin-directory
  11. 105
      spells/menu/bitcoin/configure-bitcoin
  12. 88
      spells/menu/bitcoin/install-bitcoin
  13. 4
      spells/menu/bitcoin/is-bitcoin-installed
  14. 16
      spells/menu/bitcoin/is-bitcoin-running
  15. 42
      spells/menu/bitcoin/repair-bitcoin-permissions
  16. 70
      spells/menu/bitcoin/uninstall-bitcoin
  17. 16
      spells/path-wizard
  18. 46
      spells/remove-service
  19. 43
      spells/unbind-tome
  20. 38
      tutorials/01_navigating.sh
  21. 30
      tutorials/02_variables.sh
  22. 55
      tutorials/03_comparison.sh
  23. 36
      tutorials/04_conditionals.sh
  24. 44
      tutorials/05_loops.sh
  25. 47
      tutorials/06_functions.sh
  26. 26
      tutorials/07_pipe.sh
  27. 32
      tutorials/08_permissions.sh
  28. 41
      tutorials/09_regex.sh
  29. 34
      tutorials/10_debugging.sh
  30. 19
      tutorials/11_aliases.sh
  31. 29
      tutorials/12_eval.sh
  32. 21
      tutorials/13_bg.sh
  33. 5
      tutorials/20_advanced_terminal.sh
  34. 47
      tutorials/21_parentheses.sh
  35. 10
      tutorials/22_shebang.sh
  36. 193
      tutorials/23_shell_options.sh
  37. 18
      tutorials/24_backticks.sh
  38. 109
      tutorials/25_env.sh
  39. 19
      tutorials/26_history.sh
  40. 56
      tutorials/27_best_practices.sh
  41. 127
      tutorials/28_distribution.sh
  42. 44
      tutorials/29_ssh.sh
  43. 37
      tutorials/30_git.sh
  44. 104
      tutorials/31_usability.sh

24
spells/cantrips/cd

@ -0,0 +1,24 @@
#!/bin/sh
install_cd() {
if ! grep -q "alias cd=" ~/.bashrc; then
echo "Do you wish to memorize this spell, so that you look around rooms automatically as you use 'cd'? (yes/no)"
read -r answer
if [ "$answer" = "yes" ]; then
scriptpath="$(dirname $(readlink -f $0))"
filename="$(basename "$0")"
echo "alias cd=\". $scriptpath/$filename\"" >> ~/.bashrc
echo "Spell memorized in .bashrc, so the mud will always be active in the terminal."
else
echo "The mud will only run in this shell window."
fi
fi
}
install_cd
# Call the standard cd command
builtin cd "$@"
# Look around the room
look

22
spells/cantrips/fathom-height

@ -0,0 +1,22 @@
#!/usr/bin/env sh
# This magical spell reveals the dimensions of the terminal window, displaying the width and height as if by magic.
# Define the function to calculate the dimensions of the terminal window
fathom_dimensions() {
# Get the width of the terminal window
width=$(tput cols)
# Get the height of the terminal window
height=$(tput lines)
# Output the dimensions of the terminal window
echo "Width: $width"
echo "Height: $height"
}
# Check if the script is being called from another script
if [ "${BASH_SOURCE[0]}" = "$0" ]; then
# If not, call the function
fathom_dimensions
fi

18
spells/cantrips/fathom-width

@ -0,0 +1,18 @@
#!/usr/bin/env sh
# This magical spell reveals the dimensions of the terminal window, displaying the width and height as if by magic.
# Define the function to calculate the dimensions of the terminal window
fathom_height() {
# Get the width of the terminal window
width=$(tput rows)
# Output the dimensions of the terminal window
echo "height"
}
# Check if the script is being called from another script
if [ "${BASH_SOURCE[0]}" = "$0" ]; then
# If not, call the function
fathom_dimensions
fi

2
spells/cantrips/menu

@ -11,7 +11,7 @@
. colors . colors
if [ ${#} -lt 2 ]; then if [ ${#} -lt 2 ]; then
mud-menu main-menu
exit 0 exit 0
fi fi

59
spells/install-service-template

@ -0,0 +1,59 @@
#!/bin/sh
# This script serves as a magic scroll that conjures a systemd service
# from a given template and a set of variable-value pairs
if [ $# -lt 1 ]; then
echo "Usage: $0 /path/to/service/template key=value [key=value...]"
exit 1
fi
# Ensure systemd is available
if ! command -v systemctl >/dev/null 2>&1; then
echo "Systemd is not installed or not in PATH. Exiting."
exit 1
fi
service_dir=/etc/systemd/system
template_path=$1
service_file=$(basename "$template_path")
service_path="$service_dir/$service_file"
# Ask for confirmation before overwriting an existing file
if [ -f "$service_path" ]; then
if ask_yn "Service file $service_path already exists. Overwrite?" "N"; then
echo "User chose not to overwrite. Exiting."
exit 1
fi
fi
# Prepare a sed command based on the remaining arguments
shift
substitution_cmd=""
for arg in "$@"; do
substitution_cmd="${substitution_cmd}s|\\\$${arg%%=*}|${arg#*=}|g;"
done
# Perform substitutions
sudo sh -c "sed \"$substitution_cmd\" \"$template_path\" > \"$service_path\""
# Ask for missing variables
while IFS= read -r line; do
if echo "$line" | grep -q '\$'; then
var=$(echo "$line" | sed -n -e 's/^.*\$\([A-Z_]*\).*$/\1/p')
if [ -n "$var" ]; then
echo "Enter a value for $var: "
read -r value
sed -i "s|\$$var|$value|g" "$service_path"
fi
fi
done < "$service_path"
# Set permissions
sudo chmod 644 "$service_path"
# Reload systemd
systemctl daemon-reload
echo "Service installed at $service_path"
exit 0

38
spells/is-service-installed

@ -0,0 +1,38 @@
#!/bin/sh
# This script serves as a scrying spell, checking if a given systemd service is installed
if [ $# -lt 1 ]; then
echo "Usage: $0 service_name"
exit 1
fi
# Ensure systemd is available
if ! command -v systemctl >/dev/null 2>&1; then
echo "Systemd is not installed or not in PATH. Exiting."
exit 1
fi
service_dir=/etc/systemd/system
service_name=$1
# Add .service if not present in the name
case $service_name in
*.service) ;;
*) service_name="$service_name.service" ;;
esac
service_path="$service_dir/$service_name"
# Check if service file exists
if [ -f "$service_path" ]; then
if [ -t 1 ]; then # Check if output is a terminal
echo "$service_name is installed."
fi
exit 0 # Service is installed (success)
else
if [ -t 1 ]; then # Check if output is a terminal
echo "$service_name is not installed."
fi
exit 1 # Service is not installed (failure)
fi

44
spells/menu/bitcoin/bitcoin-menu

@ -0,0 +1,44 @@
#!/bin/sh
# This script is a magical tome of sorcery, commanding the elusive entity known as Bitcoin.
. colors
# Displays the menu
display_menu() {
title="${BOLD}${CYAN}Bitcoin: $(bitcoin-status)"
blockchain_info="Display Blockchain Info%bitcoin-cli getblockchaininfo"
set_config="Configure Bitcoin%configure-bitcoin"
change_directory="Change Bitcoin Directory%change-bitcoin-directory"
clear_cache="Clear Bitcoin Cache%# coming soon"
repair_permissions="Repair Permissions%repair-bitcoin-permissions # Sometimes necessary"
exit_option="Exit%kill -2 $$" # Commands are run with 'eval' by the menu script, so we can't simply say 'exit'. The keyword $$ gets this scripts PID and the -2 code is SIGINT aka Ctrl-C
if is-bitcoin-installed; then
install_bitcoin_option="Uninstall Bitcoin%uninstall-bitcoin"
if is-service-installed bitcoin; then
install_service_option="Uninstall Bitcoin Service%remove-service bitcoin"
if is-bitcoin-running; then
bitcoin_server_option="Stop Bitcoin Service%sudo systemctl stop bitcoind"
menu "$title" "$blockchain_info" "$set_config" "$change_directory" "$clear_cache" "$repair_permissions" "$bitcoin_server_option" "$install_service_option" "$install_bitcoin_option" "$exit_option"
else
bitcoin_server_option="Start Bitcoin Service%sudo systemctl start bitcoind"
menu "$title" "$set_config" "$change_directory" "$clear_cache" "$repair_permissions" "$bitcoin_server_option" "$install_service_option" "$install_bitcoin_option" "$exit_option"
fi
else
install_service_option="Install Bitcoin Service%install-service-template ./bitcoin.service \"BITCOIND=`which bitcoind`\""
menu "$title" "$set_config" "$change_directory" "$clear_cache" "$repair_permissions" "$install_service_option" "$install_bitcoin_option" "$exit_option"
fi
else
install_bitcoin_option="Install Bitcoin%install-bitcoin"
menu "$title" "$install_bitcoin_option" "$exit_option"
fi
}
# Catch Ctrl-C and exit
trap 'echo exiting; exit' INT
# Main execution loop
while true; do
display_menu
done

64
spells/menu/bitcoin/bitcoin-status

@ -0,0 +1,64 @@
#!/bin/sh
# Get Bitcoin sync status: 'syncing', 'synced', 'unknown', or 'error'
. colors
# Returns colored text based on status
color_for_status() {
case "$1" in
"installed, running, synced")
printf "${GREEN}"
;;
"not installed")
printf "${GRAY}"
;;
"installed, not running"|"installed, running, syncing"*|"installed, running, not synced")
printf "${YELLOW}"
;;
"installed, running, error"|"*")
printf "${RED}"
;;
esac
}
get_sync_status() {
sync_status=$(bitcoin-cli getblockchaininfo 2>&1 | grep 'initialblockdownload' | awk '{print $2}' | tr -d ',')
if [ "$?" -ne "0" ]; then
echo "error"
elif [ "$sync_status" = "true" ]; then
echo "syncing"
elif [ "$sync_status" = "false" ]; then
echo "synced"
else
echo "unknown"
fi
}
# Returns colored status message
get_status() {
if is-bitcoin-installed; then
if is-bitcoin-running; then
running_status="running"
sync_status=$(get_sync_status)
if [ "$sync_status" = "synced" ]; then
install_status="installed, $running_status, synced"
elif [ "$sync_status" = "syncing" ]; then
progress=$(bitcoin-cli getblockchaininfo | grep 'progress' | awk '{print int($2*100)}')
install_status="installed, $running_status, syncing $progress%"
elif [ "$sync_status" = "unknown" ]; then
install_status="installed, $running_status, not synced"
elif [ "$sync_status" = "error" ]; then
install_status="installed, $running_status, error"
fi
else
install_status="installed, not running"
fi
else
install_status="not installed"
fi
printf "$(color_for_status "$install_status")$install_status${RESET}\n"
}
get_status

28
spells/menu/bitcoin/bitcoin.service

@ -0,0 +1,28 @@
[Unit]
Description=Bitcoin daemon
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
NotifyAccess=all
ExecStart=BITCOIND --daemonwait --pid=HOME/.bitcoin/bitcoind.pid
Type=forking
PIDFile=HOME/.bitcoin/bitcoind.pid
Restart=on-failure
TimeoutStartSec=infinity
TimeoutStopSec=600
KillSignal=SIGINT
LimitNOFILE=32768
User=USER
Group=USER
# Hardening
PrivateTmp=yes
PrivateDevices=yes
MemoryDenyWriteExecute=true
[Install]
WantedBy=multi-user.target

78
spells/menu/bitcoin/change-bitcoin-directory

@ -0,0 +1,78 @@
#!/bin/sh
# This spell alters the location of thy Bitcoin data chamber on your system.
# Check if a command needs to be re-invoked with sudo
retry_with_sudo() {
echo "Permission denied. Invoking the power of the super user..."
sudo "$@"
if [ $? -ne 0 ]; then
echo "Failed to execute with elevated privileges. Make certain thou hast the necessary permissions and try again."
exit 1
fi
}
# Check for the bitcoin.conf file
if [ ! -f "$HOME/.bitcoin/bitcoin.conf" ]; then
echo "Unable to locate bitcoin.conf. Canst thou provide its location?"
read bitcoin_conf
if [ ! -f "$bitcoin_conf" ]; then
echo "bitcoin.conf file not found at the provided location. The spell must end here."
exit 1
fi
else
bitcoin_conf="$HOME/.bitcoin/bitcoin.conf"
fi
# Get the current Bitcoin directory
current_directory=$(grep "datadir" "$bitcoin_conf" | cut -d'=' -f2)
if [ -z "$current_directory" ]; then
current_directory="$HOME/.bitcoin"
else
# Confirm that the directory actually exists
if [ ! -d "$current_directory" ]; then
echo "The Bitcoin data chamber specified in bitcoin.conf doth not exist. Please ensure the correctness of the 'datadir' value in bitcoin.conf."
exit 1
fi
echo "Verified the existence of the Bitcoin data chamber at: $current_directory"
fi
# Ask for the new directory
echo "Enter the new haven for thy Bitcoin data:"
read new_directory
# Create the new directory if it does not exist
if [ ! -d "$new_directory" ]; then
mkdir "$new_directory" || retry_with_sudo mkdir "$new_directory"
fi
# Ask user what to move
echo "What wouldst thou like to move to the new Bitcoin data haven?"
echo "1. The entire Bitcoin data chamber"
echo "2. Only the blockchain data"
echo "3. Move naught"
read move_choice
case "$move_choice" in
1)
echo "Moving the entire Bitcoin data chamber..."
mv "$current_directory"/* "$new_directory" || retry_with_sudo mv "$current_directory"/* "$new_directory"
;;
2)
echo "Moving only the blockchain data..."
mv "$current_directory/blocks" "$current_directory/chainstate" "$new_directory" || retry_with_sudo mv "$current_directory/blocks" "$current_directory/chainstate" "$new_directory"
;;
3)
echo "Moving naught..."
;;
*)
echo "Invalid choice, the spell ends here without moving anything."
exit 1
;;
esac
# Update the bitcoin.conf file to point to the new directory
awk -v path="$new_directory" '!/datadir/ {print} /datadir/ {$3 = path; print}' "$bitcoin_conf" | tee "$bitcoin_conf" >/dev/null || { retry_with_sudo awk -v path="$new_directory" '!/datadir/ {print} /datadir/ {$3 = path; print}' "$bitcoin_conf" | sudo tee "$bitcoin_conf" >/dev/null; }
echo "The Bitcoin data chamber now resides in: $new_directory"

105
spells/menu/bitcoin/configure-bitcoin

@ -0,0 +1,105 @@
#!/bin/sh
# This spell facilitates the setting of the configurations for thy Bitcoin system.
# Function to check if a command needs to be run with sudo
retry_with_sudo() {
echo "Permission denied. Invoking the power of the super user..."
sudo "$@"
if [ $? -ne 0 ]; then
echo "Failed to execute with elevated privileges. Make certain thou hast the necessary permissions and try again."
exit 1
fi
}
# Handle Ctrl-C
#trap "printf '\n'; exit 2" 2
# Create bitcoin directory and configuration file if they do not exist
mkdir -p "$HOME/.bitcoin"
touch "$HOME/.bitcoin/bitcoin.conf"
# Bitcoin defaults
defaults="proxy=127.0.0.1:9050
listen=1
bind=127.0.0.1
disablewallet=1
zmqpubrawblock=tcp://127.0.0.1:28332
zmqpubrawtx=tcp://127.0.0.1:28333"
bitcoin_conf="$HOME/.bitcoin/bitcoin.conf"
# If the file was just created (is empty), write defaults
if [ ! -s "$bitcoin_conf" ]; then
echo "$defaults" > "$bitcoin_conf"
else
ask_yn "Would you like to reset the bitcoin.conf file to defaults?" "n"
reset_conf=$?
if [ "$reset_conf" = 0 ]; then
echo "$defaults" > "$bitcoin_conf"
fi
fi
# Function to modify bitcoin.conf using awk
modify_bitcoin_conf() {
local key=$1
local value=$2
awk -v key="$key" -v value="$value" 'BEGIN {found=0} !/^#/ && $1==key {found=1; print key"="value; next} {print} END {if (!found) print key"="value}' "$bitcoin_conf" > "$bitcoin_conf.tmp" && mv "$bitcoin_conf.tmp" "$bitcoin_conf" || retry_with_sudo mv "$bitcoin_conf.tmp" "$bitcoin_conf"
}
# Pruning question and storage amount
ask_yn "Wouldst thou like to enable pruning? Pruning allows thee to reduce disk usage by discarding some transaction history." "y"
prune=$?
if [ "$prune" = 0 ]; then
modify_bitcoin_conf "prune" "1"
valid_number=false
while [ "$valid_number" = false ]; do
printf "What is the maximum disk space thou art willing to dedicate to Bitcoin in GB? (Type a number) [default: 500]: "
read -r max_disk
if [ -z "$max_disk" ]; then
max_disk=500
valid_number=true
elif validate_number "$max_disk"; then
valid_number=true
else
printf "Invalid input. Please enter a valid number.\n"
fi
done
# Convert GB to MB
max_mem=$((max_disk * 1024))
modify_bitcoin_conf "dbcache" "$max_mem"
else
modify_bitcoin_conf "prune" "0"
fi
# Network selection
ask_yn "Art thou operating on the main Bitcoin network?" "y"
mainnet=$?
if [ "$mainnet" = 0 ]; then
modify_bitcoin_conf "testnet" "0"
else
modify_bitcoin_conf "testnet" "1"
fi
# Blockchain storage location
default_data_dir="$HOME/.bitcoin/blocks"
modify_bitcoin_conf "datadir" "$default_data_dir"
ask_yn "Wouldst thou like to store the blockchain in the default location ($default_data_dir)?" "y"
alt_storage=$?
if [ "$alt_storage" = 1 ]; then
while true; do
printf "Please type the alternate path thou wouldst like to use for blockchain storage: "
read -r alt_path
if validate_path "$alt_path"; then
break
else
printf "That's not a valid UNIX path string. "
fi
done
modify_bitcoin_conf "datadir" "$alt_path"
fi
printf "Bitcoin configuration has been updated.\n"

88
spells/menu/bitcoin/install-bitcoin

@ -0,0 +1,88 @@
#!/bin/sh
# This spell installs bitcoin on almost any Linux platform, from source when possible, otherwise from precompiled binary.
# Set Bitcoin version
BITCOIN_VERSION=24.1
# Install Bitcoin from source
install_bitcoin_from_source() {
say "Installing Bitcoin Core from source"
if [ ! -e bitcoin-$BITCOIN_VERSION* ]; then
wget https://bitcoincore.org/bin/bitcoin-core-$BITCOIN_VERSION/bitcoin-$BITCOIN_VERSION.tar.gz
fi
. ./path_to_install_if_needed_script.sh boost
tar -xvf bitcoin-$BITCOIN_VERSION.tar.gz
sleep 1
cd bitcoin-$BITCOIN_VERSION
chmod +x autogen.sh
./autogen.sh
./configure --disable-wallet
make
if [ $? -ne 0 ]; then
return 1
fi
sudo make install
cd ..
return 0
}
# Install Bitcoin ARM precompiled binary
install_bitcoin_arm_binary() {
say "Installing Bitcoin Core ARM precompiled binary"
if [ ! -e bitcoin-$BITCOIN_VERSION* ]; then
wget https://bitcoincore.org/bin/bitcoin-core-$BITCOIN_VERSION/bitcoin-$BITCOIN_VERSION-arm-linux-gnueabihf.tar.gz
tar -xzf bitcoin-$BITCOIN_VERSION-arm-linux-gnueabihf.tar.gz
fi
sudo install -m 0755 -o root -g root -t /usr/local/bin bitcoin-$BITCOIN_VERSION/bin/*
}
# Install Bitcoin x86_64 precompiled binary
install_bitcoin_x86_64_binary() {
say "Installing Bitcoin Core x86_64 precompiled binary"
if [ ! -e bitcoin-$BITCOIN_VERSION* ]; then
wget https://bitcoincore.org/bin/bitcoin-core-$BITCOIN_VERSION/bitcoin-$BITCOIN_VERSION-x86_64-linux-gnu.tar.gz
tar -xzf bitcoin-$BITCOIN_VERSION-x86_64-linux-gnu.tar.gz
fi
sudo install -m 0755 -o root -g root -t /usr/local/bin bitcoin-$BITCOIN_VERSION/bin/*
}
# Install Bitcoin macOS precompiled binary
install_bitcoin_macos_binary() {
say "Installing Bitcoin Core macOS precompiled binary"
if [ ! -e bitcoin-$BITCOIN_VERSION* ]; then
wget https://bitcoincore.org/bin/bitcoin-core-$BITCOIN_VERSION/bitcoin-$BITCOIN_VERSION-osx-signed.dmg
hdiutil attach bitcoin-$BITCOIN_VERSION-osx-signed.dmg
cp -R /Volumes/Bitcoin-Core/Bitcoin-Qt.app /Applications/
hdiutil detach /Volumes/Bitcoin-Core
fi
}
# Detect the operating system
OS=$(uname -s)
# Install Bitcoin based on the OS
case $OS in
Darwin)
install_bitcoin_macos_binary
;;
Linux)
ARCH=$(uname -m)
case $ARCH in
x86_64)
if ! install_bitcoin_from_source; then
install_bitcoin_x86_64_binary
fi
;;
arm* | aarch64)
install_bitcoin_arm_binary
;;
*)
say "Unsupported architecture: $ARCH"
exit
esac
;;
*)
say "Unsupported operating system: $OS"
exit
esac

4
spells/menu/bitcoin/is-bitcoin-installed

@ -0,0 +1,4 @@
#!/bin/sh
# Returns 0 (true) if Bitcoin is installed, 1 (false) if not
command -v bitcoin-cli >/dev/null 2>&1

16
spells/menu/bitcoin/is-bitcoin-running

@ -0,0 +1,16 @@
#!/bin/sh
# This script serves as a magic mirror, reflecting the running status of Bitcoin
# Look for bitcoin process
if ps -e | grep -q '[b]itcoind'; then
if [ -t 1 ]; then # Check if output is a terminal
echo "Bitcoin is running."
fi
exit 0 # Bitcoin is running (success)
else
if [ -t 1 ]; then # Check if output is a terminal
echo "Bitcoin is not running."
fi
exit 1 # Bitcoin is not running (failure)
fi

42
spells/menu/bitcoin/repair-bitcoin-permissions

@ -0,0 +1,42 @@
#!/bin/sh
# This script sets the correct permissions on the Bitcoin configuration directory.
# Set the default Bitcoin configuration directory
default_dir="$HOME/.bitcoin"
# Check if the default directory exists
if [ -d "$default_dir" ]; then
bitcoin_dir="$default_dir"
else
# Prompt the user to enter the path to the Bitcoin configuration directory
read -p "Enter the path to the Bitcoin configuration directory: " bitcoin_dir
fi
# Check if the provided directory exists
if [ -d "$bitcoin_dir" ]; then
# Set the default permission mode
default_mode=710
# Get the configuration directory mode from bitcoin.conf
config_mode=$(grep -E '^ConfigurationDirectoryMode=' "$bitcoin_dir/bitcoin.conf" | cut -d '=' -f 2)
# If ConfigurationDirectoryMode is not specified, use the default mode
if [ -z "$config_mode" ]; then
config_mode=$default_mode
fi
# Get the current permission mode of the directory
current_mode=$(stat -c "%a" "$bitcoin_dir")
# Compare the current mode with the configured mode
if [ "$current_mode" != "$config_mode" ]; then
# Fix the permission by setting the correct mode
chmod "$config_mode" "$bitcoin_dir"
echo "The permission on the Bitcoin configuration directory has been set to $config_mode."
else
echo "The Bitcoin configuration directory is already configured with the correct permissions."
fi
else
echo "The provided directory does not exist."
fi

70
spells/menu/bitcoin/uninstall-bitcoin

@ -0,0 +1,70 @@
#!/bin/sh
# Function to check if a package is installed in Debian-based distributions
is_deb_package_installed() {
dpkg-query -W -f='${Status}' "$1" 2>/dev/null | grep -c "ok installed"
}
# Function to check if a package is installed in Redhat-based distributions
is_rpm_package_installed() {
rpm -q "$1" &> /dev/null
}
# Function to check if a package is installed in Arch-based distributions
is_arch_package_installed() {
pacman -Q "$1" &> /dev/null
}
# Uninstall Bitcoin from source
uninstall_bitcoin_from_source() {
say "Uninstalling Bitcoin Core installed from source"
sudo make uninstall
}
# Uninstall Bitcoin package
uninstall_bitcoin_package() {
say "Uninstalling Bitcoin Core package"
# Detect the operating system's package manager
if command -v apt &> /dev/null; then
if is_deb_package_installed bitcoin; then
sudo apt-get remove -y bitcoin
fi
elif command -v dnf &> /dev/null; then
if is_rpm_package_installed bitcoin; then
sudo dnf remove -y bitcoin
fi
elif command -v pacman &> /dev/null; then
if is_arch_package_installed bitcoin; then
sudo pacman -Rns bitcoin --noconfirm
fi
elif command -v brew &> /dev/null; then
if brew list --cask bitcoin-core; then
brew uninstall --cask bitcoin-core
fi
else
say "Unsupported package manager"
exit 1
fi
}
# Uninstall Bitcoin
uninstall_bitcoin() {
read -p "This will uninstall Bitcoin Core and might delete your wallet data. Are you sure? (Y/n) " yn
case $yn in
[Yy]* )
uninstall_bitcoin_from_source
uninstall_bitcoin_package
;;
[Nn]* )
say "Uninstallation cancelled"
;;
* )
say "Invalid input. Please answer with Y (yes) or N (no)"
uninstall_bitcoin
;;
esac
}
# Start the uninstallation
uninstall_bitcoin

16
spells/path-wizard

@ -22,10 +22,20 @@ fi
# Check if the directory path was provided # Check if the directory path was provided
if [ -z "$directory" ]; then if [ -z "$directory" ]; then
# If no directory path was provided, use the current directory # If no directory path was provided, use the current directory
directory=$(pwd) directory=$(pwd -P)
else else
# If a directory path was provided, expand the '~' character if necessary # If a directory path was provided, expand the '~' character if necessary
directory="$(echo "$directory" | sed "s|^~|$HOME|")" directory="$(echo "$directory" | sed "s|^~|$HOME|")"
# If the directory path is '.', convert it to the absolute path of the current directory
if [ "$directory" = "." ]; then
directory=$(pwd -P)
else
# If the directory is a relative path, convert it to an absolute path
if [ "${directory:0:1}" != "/" ]; then
directory=$(cd "$directory" && pwd -P)
fi
fi
fi fi
# Check if the directory exists # Check if the directory exists
@ -41,7 +51,7 @@ if [ ! -f "$HOME/.bashrc" ]; then
fi fi
# Check if the directory is already in the PATH variable # Check if the directory is already in the PATH variable
if grep -q "PATH=$directory" "$HOME/.bashrc"; then if grep -q "export PATH=$directory:\$PATH$" "$HOME/.bashrc"; then
# If the directory is already in the PATH variable, check if the action is 'add' # If the directory is already in the PATH variable, check if the action is 'add'
if [ "$action" = "add" ]; then if [ "$action" = "add" ]; then
echo "The directory is already in your PATH." echo "The directory is already in your PATH."
@ -49,7 +59,7 @@ if grep -q "PATH=$directory" "$HOME/.bashrc"; then
fi fi
# If the action is 'remove' and the directory is already in the PATH variable, remove the directory from the PATH variable using the 'sed' command # If the action is 'remove' and the directory is already in the PATH variable, remove the directory from the PATH variable using the 'sed' command
sed -i "\|$directory|d" "$HOME/.bashrc" sed -i "\|^export PATH=$directory:\$PATH$|d" "$HOME/.bashrc"
echo "The directory has been removed from your PATH." echo "The directory has been removed from your PATH."
else else
# If the directory is not in the PATH variable, check if the action is 'add' # If the directory is not in the PATH variable, check if the action is 'add'

46
spells/remove-service

@ -0,0 +1,46 @@
#!/bin/sh
# This script serves as an "undo" scroll for the service installation script,
# removing a systemd service that was previously created
if [ $# -lt 1 ]; then
echo "Usage: $0 service_name"
exit 1
fi
# Ensure systemd is available
if ! command -v systemctl >/dev/null 2>&1; then
echo "Systemd is not installed or not in PATH. Exiting."
exit 1
fi
service_dir=/etc/systemd/system
service_name=$1
# Add .service if not present in the name
case $service_name in
*.service) ;;
*) service_name="$service_name.service" ;;
esac
service_path="$service_dir/$service_name"
# Check if service file exists
if [ ! -f "$service_path" ]; then
echo "Service $service_name does not exist."
exit 1
fi
# Stop and disable service if it's running
if systemctl is-active --quiet "$service_name"; then
systemctl stop "$service_name"
fi
# Remove the service file
sudo rm -f "$service_path"
# Reload systemd
systemctl daemon-reload
echo "Service $service_name removed."
exit 0

43
spells/unbind-tome

@ -0,0 +1,43 @@
#!/bin/bash
# A magical spell for slicing and dicing texts and lines. Reads a text file line by line and creates a new folder with the same name as the text file, with one file for each line in the text file inside that folder. Masks any characters that are not valid for use in Unix filenames.
#!/bin/bash
###############################################################################
#
# SCRIPT: slice_text_file.sh
#
# DESCRIPTION: A magical spell for slicing and dicing texts and lines.
# Reads a text file line by line and creates a new folder with the same name
# as the text file, with one file for each line in the text file inside that
# folder. Masks any characters that are not valid for use in Unix filenames.
#
# USAGE: slice_text_file.sh path/to/text_file.txt
#
###############################################################################
# Check that a file path was provided as an argument
if [ "$#" -ne 1 ]; then
echo "Error: Please provide a file path as an argument."
exit 1
fi
# Create a folder with the same name as the text file
folder_name=$(basename "$1" | sed 's/\.[^.]*$//')
i=1
while [ -d "$folder_name" ]; do
# If the folder already exists, append a number to the folder name
folder_name="$folder_name$i"
i=$((i+1))
done
mkdir "$folder_name"
# Read the text file line by line and create a file for each line
while read -r line; do
# Mask any characters that are not valid for use in Unix filenames
# Todo: file names are all prepended with the folder name (no slash), please fix so it's just the filename
file_name=$(echo "$line" | tr -dc '[:alnum:] .,;_-' | tr ' ' '_')
# Create the file
touch "$folder_name/$file_name"
done < "$1"

38
tutorials/01_navigating.sh

@ -0,0 +1,38 @@
#!/bin/sh
# To make this script executable, use the command: chmod +x 01_navigating.sh
# To run the script, use the command: ./01_navigating.sh
echo "This spell that will teach you the basics of navigating the filesystem in POSIX-compliant Bash."
echo "To study the code of the examples, please use the command: cat 01_navigating.sh"
echo "Casting 'pwd' command..."
echo "The 'pwd' command stands for 'print working directory' and it prints the current working directory."
pwd
echo "Casting 'ls' command..."
echo "The 'ls' command stands for 'list' and it lists the files and directories in the current working directory."
ls
echo "Casting 'cd' command with '/' argument..."
echo "The 'cd' command stands for 'change directory' and it changes the current working directory."
echo "This will take us to the root directory."
cd /
pwd
echo "Casting 'cd' command with '~' argument..."
echo "This will take us to the home directory."
cd ~
pwd
echo "Casting 'mkdir' command..."
echo "The 'mkdir' command stands for 'make directory' and it creates a new directory."
echo "We are using the '-p' option which creates any necessary parent directories."
mkdir -p ~/wizardry/charms
ls ~/wizardry
echo "Casting 'rmdir' command..."
echo "The 'rmdir' command stands for 'remove directory' and it removes an empty directory."
rmdir ~/wizardry/charms
ls ~/wizardry
rmdir ~/wizardry
echo "Spell cast successfully."

30
tutorials/02_variables.sh

@ -0,0 +1,30 @@
#!/bin/sh
# To make this script executable, use the command: chmod +x 02_variables.sh
# To run the script, use the command: ./02_variables.sh
echo "This script is a spell that will teach you the basics of variables and parameter expansion in Bash."
echo "To study the code of the examples, please use the command: cat 02_variables_parameter_expansion.sh"
# Declaring a variable
ingredient="Dragon's blood"
echo "Gathering ingredients for the potion, $ingredient found."
# Accessing the value of a variable
echo "The ingredient used is: $ingredient"
# Re-assigning a variable
ingredient="Unicorn hair"
echo "Gathering ingredients for the potion, $ingredient found."
# Special variable: $#
echo "Number of ingredients passed to the script: $#"
# Special variable: $@
echo "All ingredients passed to the script: $@"
# Special variable: $?
echo "Effect of the last ingredient added: $?"
# Parameter expansion
echo "The first ingredient passed to the script is: ${1}" #todo: split this into another script, maybe between 01 and 02?
echo "Spell cast successfully."

55
tutorials/03_comparison.sh

@ -0,0 +1,55 @@
#!/bin/sh
To make this script executable, use the command: chmod +x 14_boolean_comparison.sh
To run the script, use the command: ./14_boolean_comparison.sh
echo "This spell will teach you the basics of boolean values and basic string comparison in POSIX-compliant Bash"
echo "To study the code of the examples, please use the command: cat 14_boolean_comparison.sh"
Basic string comparison
string1="magic"
string2="wizardry"
echo "Are 'magic' and 'wizardry' the same? (Should be false)"
[ "$string1" = "$string2" ]
echo $?
echo "Are 'magic' and 'magic' the same? (Should be true)"
[ "$string1" = "$string1" ]
echo $?
echo "Is 'magic' not 'wizardry'? (Should be true)"
[ "$string1" != "$string2" ]
echo $?
echo "Is 'magic' greater than 'wizardry'? (Should be false)"
[ "$string1" > "$string2" ]
echo $?
echo "Is 'wizardry' greater than 'magic'? (Should be true)"
[ "$string2" > "$string1" ]
echo $?
echo "Spell cast successfully"
# To make this script executable, use the command: chmod +x 23_boolean_values.sh
# To run the script, use the command: ./23_boolean_values.sh
echo "This spell will teach you the basics of boolean values and string comparison in POSIX-compliant Bash."
echo "To study the code of the examples, please use the command: cat 23_boolean_values.sh"
# Basic boolean values
echo $((1 == 1)) # 0
echo $((1 != 1)) # 1
echo $((1 > 2)) # 1
echo $((1 < 2)) # 0
# Basic string comparison
string1="Hello"
string2="World"
echo $((string1 == string2)) # 0
echo $((string1 != string2)) # 1
echo $((string1 > string2)) # 1
echo $((string1 < string2)) # 0
echo "Spell cast successfully"

36
tutorials/04_conditionals.sh

@ -0,0 +1,36 @@
#!/bin/sh
# To make this script executable, use the command: chmod +x 03_conditionals.sh
# To run the script, use the command: ./03_conditionals.sh
echo "This spell will teach you the basics of conditional statements in POSIX-compliant Bash."
echo "To study the code of the examples, please use the command: cat 03_conditionals.sh"
# Using if statement
echo "Checking if the ingredient is Dragon's blood"
ingredient="Dragon's blood"
if [ "$ingredient" = "Dragon's blood" ]; then
echo "The ingredient is Dragon's blood, adding it to the potion"
else
echo "The ingredient is not Dragon's blood, adding something else to the potion"
fi
# Using if-else statement
echo "Checking if the ingredient is Dragon's blood or Unicorn hair"
ingredient="Unicorn hair"
if [ "$ingredient" = "Dragon's blood" ]; then
echo "The ingredient is Dragon's blood, adding it to the potion"
elif [ "$ingredient" = "Unicorn hair" ]; then
echo "The ingredient is Unicorn hair, adding it to the potion"
else
echo "The ingredient is not Dragon's blood nor Unicorn hair, adding something else to the potion"
fi
# Using test command
echo "Checking if the number of ingredients is greater than 5"
ingredients_count=6
if test $ingredients_count -gt 5; then
echo "The number of ingredients is greater than 5"
else
echo "The number of ingredients is not greater than 5"
fi
echo "Spell cast successfully."

44
tutorials/05_loops.sh

@ -0,0 +1,44 @@
#!/bin/sh
# To make this script executable, use the command: chmod +x 04_loops.sh
# To run the script, use the command: ./04_loops.sh
echo "To study the code of the examples, please use the command: cat 04_loops.sh"
echo "This spell will teach you the basics of loops in POSIX-compliant Bash"
# Todo: give an example of using a for loop with both a number and an array (which is more like for-each)
# A for loop continues looping for as many iterations as the number of things in "in"
echo "Iterating through ingredients"
ingredients=("Dragon's blood" "Unicorn hair" "Phoenix feather")
for ingredient in "${ingredients[@]}"; do
echo " Adding $ingredient to the potion"
done
# A while loop continues as long as its test condition evaluates to true
echo "Iterating through numbers"
count=1
while test $count -le 5; do
echo " Adding number $count to the potion"
count=$((count + 1))
done
# The 'break' keyword exits out of a loop
echo "Making a second potion, only adding ingredients up through Unicorn hair"
for ingredient in "${ingredients[@]}"; do
echo " Adding $ingredient to the potion"
if [ "$ingredient" = "Unicorn hair" ]; then
echo " Found Unicorn hair, this potion is finished."
break
fi
done
# The 'continue' keyword skips ahead to the next loop iteration
echo "Making a third potion, skipping adding the Unicorn hair this time"
for ingredient in "${ingredients[@]}"; do
if [ "$ingredient" = "Unicorn hair" ]; then
echo " Found Unicorn hair, skipping adding this ingredient."
continue
fi
echo " Adding $ingredient to the potion"
done
echo "Spell cast successfully"

47
tutorials/06_functions.sh

@ -0,0 +1,47 @@
#!/bin/sh
# To make this script executable, use the command: chmod +x 05_functions.sh
# To run the script, use the command: ./05_functions.sh
echo "This spell will teach you the basics of functions in POSIX-compliant Bash"
echo "To study the code of the examples, please use the command: cat 05_functions.sh"
# Defining a function
create_potion() {
echo "Creating potion with $1 and $2"
}
# Calling a function
create_potion "Dragon's blood" "Unicorn hair"
# Defining a function with return value
calculate_price() {
echo $((10 + 20))
}
# Calling a function with return value
price=$(calculate_price)
echo "Price of the potion is $price golds"
echo "Functions can also be loaded in your .bashrc file to make them available in all terminals."
echo "For example, you can add the following line in your .bashrc file to load the 'hello' function: 'hello() { echo \"Hello, \$1\" }'"
echo "Creating a function that changes the working directory"
go_to_spell_folder() {
cd ~/spells
pwd
}
# Return statement
echo "The 'return' statement cause the function to return immediately. The return value can be captured in a variable."
my_function() {
echo "Inside the function"
return 5
echo "This line will not be executed"
}
echo "Before calling the function"
result=$(my_function)
echo "The function returned $result"
echo "After calling the function"
echo "Spell cast successfully"

26
tutorials/07_pipe.sh

@ -0,0 +1,26 @@
#!/bin/sh
# To make this script executable, use the command: chmod +x 06_pipe.sh
# To run the script, use the command: ./06_pipe.sh
echo "This spell will teach you the basics of I/O redirection and pipelines in POSIX-compliant Bash"
echo "To study the code of the examples, please use the command: cat 06_pipe.sh"
# Redirecting standard output to a file
echo "The '>' operator redirects the output of the command to the left of it and writes it to the file on the right. If the file already exists, its contents will be overwritten."
echo "Dragon's blood" > ingredient.txt
# Appending standard output to a file
echo "The '>>' operator works similar to '>', but it appends the output to the file instead of overwriting its contents."
echo "Appending to current_date.txt" >> current_date.txt
echo "Unicorn hair" >> ingredient.txt
# Redirecting standard input from a file
echo "The '<' operator redirects the contents of the file on the right as the input for the command on the left."
echo "Content of current_date.txt:"
sort < ingredient.txt
# Using pipelines
echo "The '|' operator takes the output of the command on the left and uses it as the input for the command on the right."
echo "All files in the current directory:"
ls -l | grep "^-"
echo "Spell cast successfully."

32
tutorials/08_permissions.sh

@ -0,0 +1,32 @@
#!/bin/sh
# To make this script executable, use the command: chmod +x 07_permissions.sh
# To run the script, use the command: ./07_permissions.sh
echo "This spell will teach you the basics of permissions in POSIX-compliant Bash"
echo "To study the code of the examples, please use the command: cat 07_permissions.sh"
# Execution flags
echo "The chmod command changes the permissions of a file. The permissions can be represented in two ways: octal or symbolic. "
echo "In octal representation, permissions are represented by a three-digit number, with each digit representing permissions for owner, group and others respectively. In this representation, 7 means read, write and execute permissions, 5 means read and execute permissions, and 0 means no permissions."
echo "In symbolic representation, permissions are represented by a combination of letters 'ugoa' (user, group, others, all) and '+-' (add or remove) and 'rwx' (read, write, execute) permissions. For example, 'ug+x' means add execute permission for user and group."
echo "chmod +x script.sh adds the execution flag to a script"
touch my_script.sh
chmod +x my_script.sh
ls -l my_script.sh
echo "The file my_script.sh now has the execution flag set"
echo "chmod 755 script.sh adds the execution flag and read and execute permissions for owner, group and others"
touch my_script2.sh
chmod 755 my_script2.sh
ls -l my_script2.sh
echo "The file my_script2.sh now has the execution flag and read and execute permissions for owner, group and others"
echo "chmod 700 script.sh adds the execution flag and read, write and execute permissions for owner only"
touch my_script3.sh
chmod 700 my_script3.sh
ls -l my_script3.sh
echo "The file my_script3.sh now has the execution flag and read, write and execute permissions for owner only"
echo "You can also use chown to change the ownership of a file."
echo "chown user:group script.sh changes the owner and group of the script.sh file"
echo "Spell cast successfully"

41
tutorials/09_regex.sh

@ -0,0 +1,41 @@
#!/bin/sh
# To make this script executable, use the command: chmod +x 08_regex.sh
# To run the script, use the command: ./08_regex.sh
echo "This spell will teach you the basics of regular expressions and pattern matching in POSIX-compliant Bash"
echo "To study the code of the examples, please use the command: cat 08_regex.sh"
# Basic regular expressions (special characters)
echo "Regular expressions are a way to search for patterns in text. Common special characters include:"
echo "^ - beginning of a line"
echo "$ - end of a line"
echo "* - any number of characters"
echo "? - any single character"
echo "[] - any character in the brackets"
echo "() - group characters together"
echo "| - or"
echo "\\ - escape special characters"
# grep (search in text)
echo "The grep command searches for a pattern in a file or input."
echo "grep '^root:' /etc/passwd - searches for the pattern '^root:' in the file /etc/passwd"
echo "Example: grep 'bash' /etc/passwd - searches for the pattern 'bash' in the file /etc/passwd"
grep 'bash' /etc/passwd
# sed (replace in text)
echo "The sed command is a stream editor that can perform basic text transformations on an input stream (a file or input from a pipeline)."
echo "sed 's/root/admin/' /etc/passwd - replaces the first occurence of 'root' with 'admin' in the file /etc/passwd"
echo "Example: sed 's/bash/zsh/' /etc/passwd - replaces the first occurence of 'bash' with 'zsh' in the file /etc/passwd"
echo "backup" | sed 's/backup/backup_file/'
# awk (advanced text processing)
echo "The awk command is a text processing tool that can perform more complex text transformations."
echo "awk -F: '{ print $1 }' /etc/passwd - prints the first field of each line of the file /etc/passwd, where the field separator is ':'"
awk '{ print $1 }' /etc/passwd
echo "root:x:0:0:root:/root:/bin/bash" | awk -F: '{print $1}'
# find and xargs (run command for all found files)
echo "The find command is used to search for files in a directory hierarchy. xargs is used to build and execute command lines from standard input."
echo "find / -name '*.txt' | xargs grep 'example' - searches for all .txt files in the root directory and its subdirectories, and runs 'grep 'example'' on each file found"
find /etc -name "*.conf" -exec grep "root" {} \;
echo "Spell cast successfully"

34
tutorials/10_debugging.sh

@ -0,0 +1,34 @@
#!/bin/sh
# To make this script executable, use the command: chmod +x 09_debugging.sh
# To run the script, use the command: ./09_debugging.sh
echo "This spell will teach you the basics of script debugging and error handling in POSIX-compliant Bash"
echo "To study the code of the examples, please use the command: cat 09_debugging.sh"
# echo and set -x (debugging)
echo "The echo command is used to print messages to the terminal. The set -x command enables the display of commands and their arguments as they are executed."
echo "Example: set -x; echo 'Debugging message'; set +x"
set -x; echo 'Debugging message'; set +x
# trap and signal handling (error handling)
echo "The trap command is used to catch signals sent to the script. Signals are used to communicate with processes, and are typically sent when a program needs to terminate or interrupt another program."
echo "Example: trap 'echo Signal received, exiting...; exit 0' INT; sleep 10; echo 'This line will not be executed'"
trap 'echo Signal received, exiting...; exit 0' INT; sleep 10; echo 'This line will not be executed'
# exit status and return values (error handling)
echo "Every command in Bash returns an exit status, which is the value that the command returns to the parent process. The value can be checked using the $? variable. A value of 0 indicates success, and any other value indicates failure."
echo "Example: echo $? (this should be 0)"
echo $?
# Using the exit status in a conditional statement
command
if [ $? -eq 0 ]; then
echo "Command executed successfully"
else
echo "Command failed with exit status $?"
fi
# Setting the exit status of the script
echo "You can also set the exit value of a script manually with the 'exit' command. 0 means success, every other value is an error. This script will exit with an error code of 42."
exit 42
echo "Spell cast successfully"

19
tutorials/11_aliases.sh

@ -0,0 +1,19 @@
#!/bin/sh
# To make this script executable, use the command: chmod +x 10_aliases_functions.sh
# To run the script, use the command: ./10_aliases_functions.sh
echo "This spell will teach you the basics of Aliases and Functions in POSIX-compliant Bash"
echo "To study the code of the examples, please use the command: cat 10_aliases_functions.sh"
# Aliases
echo "Creating an alias for a command"
alias ll='ls -al'
ll
echo "Aliases are used to create short, easy-to-remember commands for frequently used commands or sequences of commands."
echo "For example, we just created an alias 'll' for 'ls -al' command"
echo "Creating an alias of an alias"
alias la='ll -a'
la
echo "Spell cast successfully"

29
tutorials/12_eval.sh

@ -0,0 +1,29 @@
#!/bin/sh
echo "This spell will teach you the basics of the eval and exec functions in POSIX-compliant Bash"
echo "To study the code of the examples, please use the command: cat 11_eval.sh"
# eval function
# The eval function takes a string as an argument and treats it as if it were a command.
# It allows the user to dynamically generate and execute commands.
# Example 1: Using variables in a command
ingredient="Dragon's blood"
eval "echo Gathering ingredients for the potion: $ingredient"
# Example 2: Using command substitution
eval "echo Today is $(date)"
# Example 3: Using multiple commands
eval "echo Starting spell; sleep 2; echo Spell complete"
# exec function
# The exec function also takes a command as its argument, but it replaces the current shell process with the new command.
# This means that the new command will not run in a subshell and any changes made by the new command will affect the current shell.
# Example 1: Using exec to run a new shell
exec /bin/sh
# Example 2: Using exec to run a command
exec echo "This command is being run by exec"
echo "Spell cast successfully"

21
tutorials/13_bg.sh

@ -0,0 +1,21 @@
#!/bin/sh
# This script is a spell that will teach you about the bg and fg commands in POSIX-compliant Bash
# To study the code of the examples, please use the command: cat 12_bg.sh
echo "This spell will teach you about the bg and fg commands in POSIX-compliant Bash"
echo "To study the code of the examples, please use the command: cat 12_bg.sh"
# Running a command in the background
sleep 5 &
echo "Background task started. You can continue with other spells while waiting for it to finish."
# Listing background tasks
jobs
# Moving a background task to the foreground
fg %1
echo "Background task is now in the foreground."
# Sending a background task to the background
bg %1
echo "Foreground task is now in the background."

5
tutorials/20_advanced_terminal.sh

@ -0,0 +1,5 @@
# To move the cursor to the beginning/end of the line, use the key combination: Ctrl+A/Ctrl+E
# To delete the word before the cursor, use the key combination: Alt+Backspace
# To delete the word after the cursor, use the key combination: Alt+D

47
tutorials/21_parentheses.sh

@ -0,0 +1,47 @@
#!/bin/sh
# To make this script executable, use the command: chmod +x 21_parentheses.sh
# To run the script, use the command: ./11_parentheses.sh
echo "This spell will teach you the basics of differentiating between similar parenthetical syntax in POSIX-compliant Bash"
echo "To study the code of the examples, please use the command: cat 21_parentheses.sh"
# Using $() command substitution
echo "Using command substitution with $()"
current_date=$(date)
echo "Today's date is: $current_date"
# Using $(()) arithmetic expansion
echo "Using arithmetic expansion with $(())"
num1=5
num2=3
result=$((num1 + num2))
echo "5 + 3 = $result"
# Using string list
echo "Using string list with \"\""
ingredients="Dragon's blood Unicorn hair Phoenix feather"
echo "Ingredients: $ingredients"
# Using array
echo "Using array with ()"
ingredients=("Dragon's blood" "Unicorn hair" "Phoenix feather")
echo "Ingredients: ${ingredients[@]}"
# Using [] test command
echo "Using test command with []"
string="Dragon's blood"
if [ "$string" = "Dragon's blood" ]; then
echo "The string is Dragon's blood"
else
echo "The string is not Dragon's blood"
fi
# Using [[]] test command
echo "Using test command with [[]]"
string="Dragon's blood"
if [[ "$string" = "Dragon's blood" ]]; then
echo "The string is Dragon's blood"
else
echo "The string is not Dragon's blood"
fi
echo "Spell cast successfully."

10
tutorials/22_shebang.sh

@ -0,0 +1,10 @@
#!/bin/sh
# To make this script executable, use the command: chmod +x 22_shebang.sh
# To run the script, use the command: ./22_shebang.sh
echo "This spell will teach you the basics of script execution headers in POSIX-compliant Bash"
echo "To study the code of the examples, please use the command: cat 22_shebang.sh"
# Shebang
echo "#!/bin/sh is the shebang, it specifies the interpreter to use for running the script"
echo "#!/usr/bin/env python is an alternative shebang to use for Python scripts"
echo "#!/usr/bin/env ruby is an alternative shebang to use for Ruby scripts"

193
tutorials/23_shell_options.sh

@ -0,0 +1,193 @@
# Set command
echo "The set command is used to set or unset various shell options, as well as positional parameters."
# Setting a shell option
echo "Here we are setting the -x option, which enables the display of commands and their arguments as they are executed."
set -x
echo "This line will be displayed in the terminal, as the -x option is set."
# Unsetting a shell option
echo "Now we will unset the -x option, so command execution will no longer be displayed in the terminal."
set +x
echo "This line will not be displayed in the terminal, as the -x option is unset."
# Setting positional parameters
echo "We can also use set to set the positional parameters."
set -- "one" "two" "three"
echo "Positional parameter 1: $1"
echo "Positional parameter 2: $2"
echo "Positional parameter 3: $3"
echo "The set command allows for greater control over shell options and positional parameters."
echo "This spell will teach you about the 'set' command and different shell options in POSIX-compliant Bash"
echo "To study the code of the examples, please use the command: cat 07_variables.sh"
# Setting shell options
echo "Setting the 'errexit' option, which exits the script if any command returns a non-zero exit status"
set -e
# Using set -e to exit the script if a command fails
echo "Creating a file with touch command, which will not return a non-zero exit status"
touch example.txt
echo "Creating a file with a non-existent command, which will return a non-zero exit status and cause the script to exit"
nonexistentCommand
echo "This line will not be executed because the script exits on the previous command"
# Unsetting shell options
echo "Unsetting the 'errexit' option"
set +e
# Using set +e to continue the script even if a command fails
echo "Creating a file with a non-existent command, which will return a non-zero exit status but the script will continue"
nonexistentCommand
echo "This line will be executed because the script does not exit on the previous command"
echo "The spell has been cast successfully"
#!/bin/sh
# This script is a spell that will teach you about various shell options in POSIX-compliant Bash
# To study the code of the examples, please use the command: cat 12_shell_options.sh
# Setting the -u option
echo "Setting the -u option: unset variables will cause an error"
set -u
# Demonstrating the effect of the -u option
echo "Value of unset variable: $unset_variable"
# Setting the -e option
echo "Setting the -e option: commands that return non-zero exit status will cause an error"
set -e
# Demonstrating the effect of the -e option
echo "This command will fail: false"
# Setting the -f option
echo "Setting the -f option: file name generation using wildcard characters will be disabled"
set -f
# Demonstrating the effect of the -f option
echo "List of files: *"
echo "Casting the spell is finished, check the code of the spell by using 'cat 12_shell_options.sh' command"
# This script is a spell that will teach you about the n, v, and o options in POSIX-compliant Bash.
# To study the code of the examples, please use the command: cat 12_shell_options_2.sh
echo "This spell will teach you about the n, v, and o options in POSIX-compliant Bash"
echo "Using the -n option to prevent execution of the commands"
set -n
echo "This line won't be executed"
set +n
echo "Using the -v option to print commands before execution"
set -v
echo "This line will be printed before execution"
set +v
echo "Using the -o option to set an option"
set -o nounset
echo "This line will trigger an error if the variable is not set"
set +o nounset
echo "Casting the spell is finished, check the code of the spell by using 'cat 12_shell_options_2.sh' command"
# This script is a spell that will teach you about some additional shell options in POSIX-compliant Bash.
# To study the code of the examples, please use the command: cat script_name.sh
# -u option: Treat unset variables as an error and exit
# This will cause the script to exit if an unset variable is used
set -u
echo "Using unset variable: $unset_variable" # This will cause the script to exit with an error
# -C option: Prevent file overwriting with >
# This will cause the script to exit if the file already exists
set -C
echo "Hello World" > existing_file.txt # This will cause the script to exit with an error
# -B option: Enable brace expansion
echo {a,b,c} # This will print "a b c"
echo {1..3} # This will print "1 2 3"
# -e option: Exit immediately if a command exits with a non-zero status
set -e
ls does_not_exist.txt # This will cause the script to exit with an error
echo "Casting the spell is finished, check the code of the spell by using 'cat script_name.sh' command"
# This script is a spell that will teach you about some advanced shell options in POSIX-compliant Bash
# -m: monitor mode
# This option will automatically exit the shell when all jobs have completed
set -m
sleep 10 &
wait
echo "All jobs have completed and the shell has exited"
# -r: restricted mode
# This option will restrict the shell's abilities, making it more secure by disabling certain dangerous commands
set -r
echo "This line will be executed"
cp /etc/passwd /tmp/passwd # this command will be disabled and the script will exit with an error
echo "This line won't be executed"
# -s: silent mode
# This option will make the shell more silent by not printing commands before they are executed
set -s
echo "This line will be executed"
echo "This line won't be printed"
# -h: hash all commands
# This option will make the shell remember the location of commands as they are executed
# so that next time the same command is executed, it will be faster
set -h
which ls # this command will be hashed
which ls # this command will be faster because the location of ls has been hashed
# -a: export all variables
# This option will export all variables to child processes
set -a
myvar="Hello World"
./script.sh # in script.sh, myvar will be available
# -b: notify of background completion
# This option will notify the user when a background job has completed
set -b
sleep 10 &
echo "Waiting for background job to complete"
wait
echo "Background job has completed"
# -f: disable file name generation (globbing)
# This option will disable file name generation, so that wildcards like * won't be expanded
set -f
echo * # this will print * instead of all files in the current directory
# -i: interactive mode
# This option will make the shell more interactive, by keeping the terminal open after a script has executed
set -i
echo "The terminal will remain open after this script has executed"
# -P: physical directory, don't follow symlinks
# This option will make the cd command not follow symlinks
set -P
ln -s /usr/local /tmp/locallink
cd /tmp/locallink
pwd # this will print /tmp/locallink
# Setting the -T option
set -T
# Attempting to execute a binary that's not in the PATH
./nonexistent_binary
# Outputting the exit status of the last command
echo "Exit status of last command: $?"
echo "Casting the spell is finished,"

18
tutorials/24_backticks.sh

@ -0,0 +1,18 @@
#!/bin/sh
# To make this script executable, use the command: chmod +x 24_backticks.sh
# To run the script, use the command: ./24_backticks.sh
echo "This spell will teach you the basics of capturing command output with backticks in POSIX-compliant Bash"
echo "To study the code of the examples, please use the command: cat 24_backticks.sh"
# Capturing output with backticks
current_dir=`pwd`
echo "You are currently in the $current_dir directory"
# Assigning output of multiple commands to a variable
system_info=`uname -a; uptime`
echo "System information: $system_info"
# Using backticks in command substitution
echo "The current date and time is `date`"
echo "Spell cast successfully"

109
tutorials/25_env.sh

@ -0,0 +1,109 @@
#!/bin/sh
# This spell will teach you how to work with environment variables in POSIX-compliant Bash
# This spell will teach you about environment variables, which are variables that are accessible to all processes running in the operating system. They store information such as system paths, user preferences, and other settings.
# Limitations on naming conventions vary by operating system, but in general, they can only contain alphanumeric characters and underscores, and have a maximum length of around 1024 characters. They cannot be aliased, but they can be exported and referenced in the .bashrc file.
echo "To cast the spell, please use the command: ./25_env.sh"
# Setting an environment variable
export MY_ENV_VAR="This is my environment variable"
echo "Environment variable MY_ENV_VAR is set to $MY_ENV_VAR"
# Checking if an environment variable is set
if [ -z "$MY_ENV_VAR" ]; then
echo "MY_ENV_VAR is not set"
else
echo "MY_ENV_VAR is set to $MY_ENV_VAR"
fi
# Exporting a variable in .bashrc
echo "export MY_ENV_VAR_IN_BASHRC=This variable is set in .bashrc" >> ~/.bashrc
# Loading .bashrc
source ~/.bashrc
echo "MY_ENV_VAR_IN_BASHRC is set to $MY_ENV_VAR_IN_BASHRC"
echo "Spell cast successfully"
#!/bin/sh
# This spell will teach you about environment variables and exporting in POSIX-compliant Bash
# Environment variables are variables that contain information about the environment in which a process runs. They can be used to set various options and make certain information available to processes.
# The limitations on names of environment variables are that they can only contain letters, numbers, and underscores, and the maximum length is determined by the system's limit on the length of environment variable strings. Environment variables cannot be aliased.
# Setting an environment variable
export MY_ENV_VAR="This is my environment variable"
echo "MY_ENV_VAR is set to: $MY_ENV_VAR"
# Accessing an environment variable
echo "The value of MY_ENV_VAR is: $MY_ENV_VAR"
# Exporting an environment variable in .bashrc
echo "export MY_ENV_VAR=\"This is my environment variable\"" >> ~/.bashrc
# Accessing an exported environment variable in a new terminal session
echo "The value of MY_ENV_VAR is: $MY_ENV_VAR"
echo "Spell cast successfully"
#!/bin/sh
# This spell will teach you the basics of environment variables in POSIX-compliant Bash
# To study the code of the examples, please use the command: cat 25_env.sh
echo "Welcome to the land of magic, where we will be learning about environment variables"
# Setting an environment variable
export MY_VAR="Dragon's breath"
echo "The variable MY_VAR has been set to $MY_VAR"
# Listing all environment variables
echo "All the current environment variables are:"
printenv
# Unsetting an environment variable
unset MY_VAR
echo "The variable MY_VAR has been unset"
# Checking if a variable is set
if [ -z "$MY_VAR" ]; then
echo "MY_VAR is unset"
else
echo "MY_VAR is set"
fi
# Using an environment variable in a command
export FILE_LOCATION="/usr/local/spells"
ls $FILE_LOCATION
echo "Spell cast successfully"
#!/bin/sh
# This spell will teach you the basics of working with environment variables in POSIX-compliant Bash
# Listing all environment variables
echo "The current environment variables are:"
printenv
# Setting an environment variable
export MY_VAR="Dragon's breath potion"
# Checking if a variable is set
if [ -z "$MY_VAR" ]; then
echo "MY_VAR is not set"
else
echo "MY_VAR is set to $MY_VAR"
fi
# Using an environment variable in a command
echo "The ingredients of the $MY_VAR are:"
cat potion_recipe.txt
# Unsetting an environment variable
unset MY_VAR
# Special predefined environment variables
echo "The current working directory is $PWD"
echo "The current user is $USER"
echo "The current shell is $SHELL"
echo "Spell cast successfully"

19
tutorials/26_history.sh

@ -0,0 +1,19 @@
#!/bin/bash
# This spell will teach you the basics of using the history command in Bash
echo "The history command allows you to view and manipulate your command history."
echo "To view your command history, use the command: history"
# View the last 10 commands
history 10
# Search for a specific command in history
history | grep "spell"
# Run a specific command from history
!3
# Clear your command history
history -c
echo "History spell cast successfully!"

56
tutorials/27_best_practices.sh

@ -0,0 +1,56 @@
#!/bin/sh
# This spell will teach you the basics of Bash scripting best practices and optimization techniques
echo "The magic of scripting can be improved with the following best practices and optimization techniques:"
# 1. Use shebang
# Always use the shebang line (#!/bin/sh or #!/bin/bash) at the top of your script to specify the interpreter.
# 2. Use single quotes for strings
# Use single quotes for strings to prevent variable and command substitution.
string='Hello, World!'
echo $string # This will print 'Hello, World!'
# 3. Avoid using unnecessary subshells
# Avoid using subshells by using command substitution with $() instead of backticks `` or $(command).
result=$(command) # Better
result=`command` # Not recommended
# 4. Use double quotes for variables
# Use double quotes for variables to prevent word splitting and globbing.
name="John Doe"
echo "My name is $name" # This will print 'My name is John Doe'
# 5. Declare variables as local
# Declare variables as local when they are only used within a function.
my_function() {
local my_variable="Hello, World!"
echo $my_variable
}
my_function
# 6. Use the -e option for echo
# Use the -e option for echo to enable the interpretation of backslash escapes.
echo -e "This is a new line \nThis is a tab \t"
# 7. Use the -n option for echo
# Use the -n option for echo to suppress the trailing newline.
echo -n "Hello, "; echo "World!" # This will print 'Hello, World!' on the same line
# 8. Use the -x option for debugging
# Use the -x option to debug your script by displaying commands and their arguments as they are executed.
# 9. Use the -u option for undefined variables
# Use the -u option to catch references to uninitialized variables.
# 10. Use the -o option for options
# Use the -o option to enable or disable options within a script.
echo "Spell cast successfully"

127
tutorials/28_distribution.sh

@ -0,0 +1,127 @@
#!/bin/bash
# Spell cast: Script packaging and distribution
# Introduction:
# Packaging and distributing your scripts is an important step in making them usable by others.
# This spell will teach you the basics of creating an executable file and packaging it for distribution.
# Creating an executable file
# In order to run a script, it needs to have the correct permissions set.
# To make a script executable, you can use the chmod command.
# For example, the following command will give the owner and group execute permissions:
chmod u+x script_name.sh
# This will allow the script to be run by typing its name in the terminal.
# Packaging for distribution
# Once your script is executable, you can package it for distribution.
# One common way to do this is to create a .tar file which can be easily extracted on other machines.
# The following command will create a .tar file of your script:
tar -cvf script_name.tar script_name.sh
# You can then distribute the .tar file to others who can extract it and run the script.
# Another way to package your script is to create a .deb package using the dpkg command.
# This is useful if you want to distribute your script as a package that can be easily installed and uninstalled.
# To create a .deb package, you will need to create a control file and a post-installation script.
# Once you have those, you can use the following command to create the package:
dpkg-deb --build script_name
# You can then distribute the .deb package to others who can install it using the dpkg command.
# Conclusion:
# These are just a few basic techniques for packaging and distributing your scripts.
# With these skills, you will be able to share your scripts with others and make them easily usable.
# Spell cast successfully!
#!/bin/bash
# This spell will teach you about Bash Script Packaging and Distribution
echo "Welcome to the Script Packaging and Distribution tutorial"
echo "To study the code of the examples, please use the command: cat 27_script_packaging.sh"
# Creating an executable file
# In order for your script to be executed, it needs to have the execute permission.
# This can be done by using the chmod command, such as chmod +x script.sh.
# This will give the owner of the file execute permission, allowing them to run the script.
chmod +x script.sh
# Creating a .deb package
# A .deb package is a format used for software distribution in Debian based systems.
# This can be useful for distribution of your script to other users on the same system.
# One way to create a .deb package is to use the checkinstall command,
# which will create a .deb package of the script and install it on the system.
checkinstall -D --install=no --pkgname=my_script --pkgversion="1.0" --pkgrelease="1" --pakdir=../ --maintainer=myemail@example.com --exclude=/.git/ -y
# Creating a .rpm package
# A .rpm package is a format used for software distribution in Red Hat based systems.
# This can be useful for distribution of your script to other users on the same system.
# One way to create a .rpm package is to use the rpm command,
# which will create a .rpm package of the script and install it on the system.
rpmbuild -bb --define "_topdir $PWD" --define "debug_package %{nil}" my_script.spec
# Creating a standalone executable
# A standalone executable is a single file that contains all the necessary dependencies
# for the script to run, making it easy to distribute to other users.
# One way to create a standalone executable is to use the pyinstaller command for python scripts,
# or the cxfreeze command for python scripts.
pyinstaller --onefile script.py
cxfreeze script.py --target-dir dist
echo "Script packaging and distribution spell cast successfully"
#!/bin/sh
# To make this script executable, use the command: chmod +x script_name.sh
# This spell will teach you how to package and distribute your Bash scripts
# Creating a self-contained script
echo "Creating a self-contained script"
cat > self_contained.sh <<'EOF'
#!/bin/bash
# Your script code here
EOF
chmod +x self_contained.sh
# Using a package manager
echo "Using a package manager"
apt-get install bash-completion
# Creating an executable file
echo "Creating an executable file with the command chmod +x script_name.sh"
chmod +x script_name.sh
# Creating a tarball
echo "Creating a tarball with the command tar -cvzf script_name.tar.gz script_name.sh"
tar -cvzf script_name.tar.gz script_name.sh
# Creating a deb package
echo "Creating a deb package with the command dpkg-deb --build script_name"
dpkg-deb --build script_name
echo "Spell cast successfully"
#!/bin/bash
# To cast this spell, use the command: ./27_script_packaging.sh
echo "This spell will teach you how to package and distribute your Bash scripts"
echo "To study the code of the examples, please use the command: cat 27_script_packaging.sh"
# Creating an executable file
echo "Creating an executable file for the script 'my_script.sh'"
chmod +x my_script.sh
# Compressing the script
echo "Compressing the script for distribution"
tar -czf my_script.tar.gz my_script.sh
# Specifying interpreter in script
echo "Specifying interpreter in script for portability"
echo '#!/usr/bin/env bash' | cat - my_script.sh > temp && mv temp my_script.sh
# Adding a shebang line
echo "Adding a shebang line to the script"
echo '#!/bin/bash' | cat - my_script.sh > temp && mv temp my_script.sh
echo "Spell cast successfully"

44
tutorials/29_ssh.sh

@ -0,0 +1,44 @@
#!/bin/bash
# Spell cast: Secure Shell (ssh) and Secure Copy (scp)
echo "Welcome, apprentice. Today we will be learning about the Secure Shell (ssh) and Secure Copy (scp) commands."
echo "These spells are crucial for securely accessing remote servers and copying files between them."
echo "Let's begin by setting up an ssh key. This will allow us to securely log in to a remote server without using a password."
# Generate an ssh key
ssh-keygen -t rsa
echo "Your ssh key has been generated. Now we need to add it to the remote server's authorized_keys file"
# Add ssh key to remote server
ssh-copy-id user@remote_server
echo "Your ssh key has been added to the remote server. You can now log in to the remote server using ssh."
# Log in to remote server
ssh user@remote_server
echo "Now that we are logged in to the remote server, let's try copying a file using the secure copy (scp) command."
# Copy file from local to remote server
scp file.txt user@remote_server:/path/to/file.txt
echo "The file has been successfully copied to the remote server. You can also copy files from the remote server to your local machine using scp."
# Copy file from remote to local server
scp user@remote_server:/path/to/file.txt file.txt
echo "You can also copy entire directories using the -r flag."
# Copy directory from local to remote server
scp -r local_directory user@remote_server:/path/to/remote_directory
echo "You can also copy files and directories between remote servers"
# Copy file from remote server 1 to remote server 2
scp user1@remote_server1:/path/to/file.txt user2@remote_server2:/path/to/file.txt
echo "And that's it for our lesson on ssh and scp. Remember, these spells are powerful tools for securely accessing and transferring files between servers. Use them wisely."
echo "Spell cast successfully!"

37
tutorials/30_git.sh

@ -0,0 +1,37 @@
#!/bin/bash
# Spell cast: Git Magic
# This spell will teach you the basics of using git for common tasks.
# First, let's initialize a git repository in the current directory
git init
# Now, let's create a new file and add it to the repository
touch newfile.txt
git add newfile.txt
# We can check the status of our repository to see what changes have been made
git status
# To commit the changes, we use the commit command
git commit -m "Added newfile.txt"
# To clone a repository from a remote source, we use the clone command
git clone https://github.com/user/repo.git
# To add changes to the repository
echo "Hello, Git!" >> newfile.txt
git add newfile.txt
git commit -m "Modified newfile.txt"
# To remove a file from the repository
git rm newfile.txt
git commit -m "Removed newfile.txt"
# To reset changes to a file
git reset newfile.txt
# To reset files to the last version
git reset --hard
# Spell cast successfully!

104
tutorials/31_usability.sh

@ -0,0 +1,104 @@
#!/bin/bash
# Spell cast successfully!
# This spell will teach you about best practices for making UNIX scripts and command line utilities usable
# One important aspect of script usability is providing clear and concise usage instructions.
# You can do this by adding a usage function or a help flag, such as `-h` or `--help`.
usage() {
echo "Usage: $0 [-h] [-v] [-f file] arg1 arg2"
}
while getopts "hvf:" opt; do
case ${opt} in
h )
usage
exit 0
;;
v )
echo "Verbose mode on"
;;
f )
file="$OPTARG"
;;
\? )
usage
exit 1
;;
esac
done
shift $((OPTIND -1))
# Another aspect of usability is providing clear and informative error messages.
# This can help users quickly understand what went wrong and how to fix it.
if [[ -z $1 ]]; then
echo "Error: missing required argument arg1"
usage
exit 1
fi
if [[ ! -f $file ]]; then
echo "Error: $file is not a valid file"
exit 1
fi
# You can also improve usability by providing a consistent interface and adhering to conventions.
# For example, using long options with a double dash, like `--help` is more user-friendly than using short options with a single dash like `-h`.
echo "arg1: $1"
echo "arg2: $2"
echo "file: $file"
# Additionally, providing tab-completion options for your script can greatly enhance usability.
# Lastly, testing your script with different inputs and edge cases can help ensure it is robust and usable for a wide range of users.
# Spell cast successfully!
#!/bin/bash
# The Very Usable, the most usable script
# By studying this spell, your scripts shall be top-notch and fleet
# With usage and help options, your users shall never be lost
# And clear error messages, at any cost
# First, let's add usage and help flags
while getopts ":h" opt; do
case $opt in
h)
echo "Usage: $(basename $0) [-h] [arguments]"
echo "This is a highly usable script that demonstrates best practices for making unix scripts and command line utilities usable."
exit 0
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
esac
done
# Now let's add some actions for the script
if [ $# -eq 0 ]; then
echo "No arguments provided. Use -h flag for help." >&2
exit 1
else
echo "Performing actions with provided arguments: $@"
fi
# Let's make sure our script exits with appropriate status codes
exit_status=0
# And let's add some error handling
error_message="Error: unknown error"
trap 'echo $error_message; exit $exit_status' ERR
# Now, let's add some actions that may fail
false # this command always exits with status 1
# Let's update our error message and exit status before exiting
error_message="Error: false command failed"
exit_status=1
# The Very Usable spell has been cast successfully
Loading…
Cancel
Save