From 00f310906c58a49d3623d0168316c050c9e7bd59 Mon Sep 17 00:00:00 2001 From: deicidus Date: Mon, 12 Jun 2023 07:16:22 -0700 Subject: [PATCH] added service manager and tutorials --- spells/cantrips/cd | 24 +++ spells/cantrips/fathom-height | 22 ++ spells/cantrips/fathom-width | 18 ++ spells/cantrips/menu | 2 +- spells/install-service-template | 59 ++++++ spells/is-service-installed | 38 ++++ spells/menu/bitcoin/bitcoin-menu | 44 ++++ spells/menu/bitcoin/bitcoin-status | 64 ++++++ spells/menu/bitcoin/bitcoin.service | 28 +++ spells/menu/bitcoin/change-bitcoin-directory | 78 +++++++ spells/menu/bitcoin/configure-bitcoin | 105 ++++++++++ spells/menu/bitcoin/install-bitcoin | 88 ++++++++ spells/menu/bitcoin/is-bitcoin-installed | 4 + spells/menu/bitcoin/is-bitcoin-running | 16 ++ .../menu/bitcoin/repair-bitcoin-permissions | 42 ++++ spells/menu/bitcoin/uninstall-bitcoin | 70 +++++++ spells/path-wizard | 16 +- spells/remove-service | 46 +++++ spells/unbind-tome | 43 ++++ tutorials/01_navigating.sh | 38 ++++ tutorials/02_variables.sh | 30 +++ tutorials/03_comparison.sh | 55 +++++ tutorials/04_conditionals.sh | 36 ++++ tutorials/05_loops.sh | 44 ++++ tutorials/06_functions.sh | 47 +++++ tutorials/07_pipe.sh | 26 +++ tutorials/08_permissions.sh | 32 +++ tutorials/09_regex.sh | 41 ++++ tutorials/10_debugging.sh | 34 +++ tutorials/11_aliases.sh | 19 ++ tutorials/12_eval.sh | 29 +++ tutorials/13_bg.sh | 21 ++ tutorials/20_advanced_terminal.sh | 5 + tutorials/21_parentheses.sh | 47 +++++ tutorials/22_shebang.sh | 10 + tutorials/23_shell_options.sh | 193 ++++++++++++++++++ tutorials/24_backticks.sh | 18 ++ tutorials/25_env.sh | 109 ++++++++++ tutorials/26_history.sh | 19 ++ tutorials/27_best_practices.sh | 56 +++++ tutorials/28_distribution.sh | 127 ++++++++++++ tutorials/29_ssh.sh | 44 ++++ tutorials/30_git.sh | 37 ++++ tutorials/31_usability.sh | 104 ++++++++++ 44 files changed, 2024 insertions(+), 4 deletions(-) create mode 100755 spells/cantrips/cd create mode 100755 spells/cantrips/fathom-height create mode 100755 spells/cantrips/fathom-width create mode 100755 spells/install-service-template create mode 100755 spells/is-service-installed create mode 100755 spells/menu/bitcoin/bitcoin-menu create mode 100755 spells/menu/bitcoin/bitcoin-status create mode 100644 spells/menu/bitcoin/bitcoin.service create mode 100755 spells/menu/bitcoin/change-bitcoin-directory create mode 100755 spells/menu/bitcoin/configure-bitcoin create mode 100755 spells/menu/bitcoin/install-bitcoin create mode 100755 spells/menu/bitcoin/is-bitcoin-installed create mode 100755 spells/menu/bitcoin/is-bitcoin-running create mode 100755 spells/menu/bitcoin/repair-bitcoin-permissions create mode 100755 spells/menu/bitcoin/uninstall-bitcoin create mode 100755 spells/remove-service create mode 100755 spells/unbind-tome create mode 100755 tutorials/01_navigating.sh create mode 100755 tutorials/02_variables.sh create mode 100644 tutorials/03_comparison.sh create mode 100755 tutorials/04_conditionals.sh create mode 100755 tutorials/05_loops.sh create mode 100644 tutorials/06_functions.sh create mode 100644 tutorials/07_pipe.sh create mode 100644 tutorials/08_permissions.sh create mode 100644 tutorials/09_regex.sh create mode 100755 tutorials/10_debugging.sh create mode 100644 tutorials/11_aliases.sh create mode 100644 tutorials/12_eval.sh create mode 100644 tutorials/13_bg.sh create mode 100644 tutorials/20_advanced_terminal.sh create mode 100644 tutorials/21_parentheses.sh create mode 100644 tutorials/22_shebang.sh create mode 100644 tutorials/23_shell_options.sh create mode 100644 tutorials/24_backticks.sh create mode 100644 tutorials/25_env.sh create mode 100644 tutorials/26_history.sh create mode 100644 tutorials/27_best_practices.sh create mode 100644 tutorials/28_distribution.sh create mode 100644 tutorials/29_ssh.sh create mode 100644 tutorials/30_git.sh create mode 100644 tutorials/31_usability.sh diff --git a/spells/cantrips/cd b/spells/cantrips/cd new file mode 100755 index 0000000..1bef9ac --- /dev/null +++ b/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 diff --git a/spells/cantrips/fathom-height b/spells/cantrips/fathom-height new file mode 100755 index 0000000..f7e3b52 --- /dev/null +++ b/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 \ No newline at end of file diff --git a/spells/cantrips/fathom-width b/spells/cantrips/fathom-width new file mode 100755 index 0000000..eeadd81 --- /dev/null +++ b/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 \ No newline at end of file diff --git a/spells/cantrips/menu b/spells/cantrips/menu index 5bf3f66..2a97c89 100755 --- a/spells/cantrips/menu +++ b/spells/cantrips/menu @@ -11,7 +11,7 @@ . colors if [ ${#} -lt 2 ]; then - mud-menu + main-menu exit 0 fi diff --git a/spells/install-service-template b/spells/install-service-template new file mode 100755 index 0000000..a7829ab --- /dev/null +++ b/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 \ No newline at end of file diff --git a/spells/is-service-installed b/spells/is-service-installed new file mode 100755 index 0000000..b271b91 --- /dev/null +++ b/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 \ No newline at end of file diff --git a/spells/menu/bitcoin/bitcoin-menu b/spells/menu/bitcoin/bitcoin-menu new file mode 100755 index 0000000..66999c0 --- /dev/null +++ b/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 \ No newline at end of file diff --git a/spells/menu/bitcoin/bitcoin-status b/spells/menu/bitcoin/bitcoin-status new file mode 100755 index 0000000..dbaedc7 --- /dev/null +++ b/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 \ No newline at end of file diff --git a/spells/menu/bitcoin/bitcoin.service b/spells/menu/bitcoin/bitcoin.service new file mode 100644 index 0000000..bf79acf --- /dev/null +++ b/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 diff --git a/spells/menu/bitcoin/change-bitcoin-directory b/spells/menu/bitcoin/change-bitcoin-directory new file mode 100755 index 0000000..8063af2 --- /dev/null +++ b/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" \ No newline at end of file diff --git a/spells/menu/bitcoin/configure-bitcoin b/spells/menu/bitcoin/configure-bitcoin new file mode 100755 index 0000000..dc8944e --- /dev/null +++ b/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" \ No newline at end of file diff --git a/spells/menu/bitcoin/install-bitcoin b/spells/menu/bitcoin/install-bitcoin new file mode 100755 index 0000000..e2b57a7 --- /dev/null +++ b/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 \ No newline at end of file diff --git a/spells/menu/bitcoin/is-bitcoin-installed b/spells/menu/bitcoin/is-bitcoin-installed new file mode 100755 index 0000000..ca2ebf0 --- /dev/null +++ b/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 \ No newline at end of file diff --git a/spells/menu/bitcoin/is-bitcoin-running b/spells/menu/bitcoin/is-bitcoin-running new file mode 100755 index 0000000..a9df31e --- /dev/null +++ b/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 \ No newline at end of file diff --git a/spells/menu/bitcoin/repair-bitcoin-permissions b/spells/menu/bitcoin/repair-bitcoin-permissions new file mode 100755 index 0000000..b49fd3b --- /dev/null +++ b/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 \ No newline at end of file diff --git a/spells/menu/bitcoin/uninstall-bitcoin b/spells/menu/bitcoin/uninstall-bitcoin new file mode 100755 index 0000000..6296b46 --- /dev/null +++ b/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 \ No newline at end of file diff --git a/spells/path-wizard b/spells/path-wizard index 3ae9ad3..7117d31 100755 --- a/spells/path-wizard +++ b/spells/path-wizard @@ -22,10 +22,20 @@ fi # Check if the directory path was provided if [ -z "$directory" ]; then # If no directory path was provided, use the current directory - directory=$(pwd) + directory=$(pwd -P) else # If a directory path was provided, expand the '~' character if necessary 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 # Check if the directory exists @@ -41,7 +51,7 @@ if [ ! -f "$HOME/.bashrc" ]; then fi # 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 [ "$action" = "add" ]; then echo "The directory is already in your PATH." @@ -49,7 +59,7 @@ if grep -q "PATH=$directory" "$HOME/.bashrc"; then 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 - sed -i "\|$directory|d" "$HOME/.bashrc" + sed -i "\|^export PATH=$directory:\$PATH$|d" "$HOME/.bashrc" echo "The directory has been removed from your PATH." else # If the directory is not in the PATH variable, check if the action is 'add' diff --git a/spells/remove-service b/spells/remove-service new file mode 100755 index 0000000..934f569 --- /dev/null +++ b/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 \ No newline at end of file diff --git a/spells/unbind-tome b/spells/unbind-tome new file mode 100755 index 0000000..da3d91a --- /dev/null +++ b/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" diff --git a/tutorials/01_navigating.sh b/tutorials/01_navigating.sh new file mode 100755 index 0000000..89e3142 --- /dev/null +++ b/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." diff --git a/tutorials/02_variables.sh b/tutorials/02_variables.sh new file mode 100755 index 0000000..6ab323e --- /dev/null +++ b/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." diff --git a/tutorials/03_comparison.sh b/tutorials/03_comparison.sh new file mode 100644 index 0000000..fa09ebd --- /dev/null +++ b/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" \ No newline at end of file diff --git a/tutorials/04_conditionals.sh b/tutorials/04_conditionals.sh new file mode 100755 index 0000000..060c867 --- /dev/null +++ b/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." diff --git a/tutorials/05_loops.sh b/tutorials/05_loops.sh new file mode 100755 index 0000000..577f31a --- /dev/null +++ b/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" \ No newline at end of file diff --git a/tutorials/06_functions.sh b/tutorials/06_functions.sh new file mode 100644 index 0000000..4fc85c0 --- /dev/null +++ b/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" + diff --git a/tutorials/07_pipe.sh b/tutorials/07_pipe.sh new file mode 100644 index 0000000..2ed71b2 --- /dev/null +++ b/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." diff --git a/tutorials/08_permissions.sh b/tutorials/08_permissions.sh new file mode 100644 index 0000000..b9d6191 --- /dev/null +++ b/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" \ No newline at end of file diff --git a/tutorials/09_regex.sh b/tutorials/09_regex.sh new file mode 100644 index 0000000..afa7bf3 --- /dev/null +++ b/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" diff --git a/tutorials/10_debugging.sh b/tutorials/10_debugging.sh new file mode 100755 index 0000000..f733c17 --- /dev/null +++ b/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" diff --git a/tutorials/11_aliases.sh b/tutorials/11_aliases.sh new file mode 100644 index 0000000..5444209 --- /dev/null +++ b/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" diff --git a/tutorials/12_eval.sh b/tutorials/12_eval.sh new file mode 100644 index 0000000..883c444 --- /dev/null +++ b/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" diff --git a/tutorials/13_bg.sh b/tutorials/13_bg.sh new file mode 100644 index 0000000..209deb0 --- /dev/null +++ b/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." diff --git a/tutorials/20_advanced_terminal.sh b/tutorials/20_advanced_terminal.sh new file mode 100644 index 0000000..38434c1 --- /dev/null +++ b/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 \ No newline at end of file diff --git a/tutorials/21_parentheses.sh b/tutorials/21_parentheses.sh new file mode 100644 index 0000000..2e5f484 --- /dev/null +++ b/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." diff --git a/tutorials/22_shebang.sh b/tutorials/22_shebang.sh new file mode 100644 index 0000000..4369589 --- /dev/null +++ b/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" diff --git a/tutorials/23_shell_options.sh b/tutorials/23_shell_options.sh new file mode 100644 index 0000000..c5d1926 --- /dev/null +++ b/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," diff --git a/tutorials/24_backticks.sh b/tutorials/24_backticks.sh new file mode 100644 index 0000000..f262a0e --- /dev/null +++ b/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" diff --git a/tutorials/25_env.sh b/tutorials/25_env.sh new file mode 100644 index 0000000..316fe0b --- /dev/null +++ b/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" \ No newline at end of file diff --git a/tutorials/26_history.sh b/tutorials/26_history.sh new file mode 100644 index 0000000..1de87b1 --- /dev/null +++ b/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!" diff --git a/tutorials/27_best_practices.sh b/tutorials/27_best_practices.sh new file mode 100644 index 0000000..271a9fc --- /dev/null +++ b/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" diff --git a/tutorials/28_distribution.sh b/tutorials/28_distribution.sh new file mode 100644 index 0000000..1fe7d6d --- /dev/null +++ b/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" \ No newline at end of file diff --git a/tutorials/29_ssh.sh b/tutorials/29_ssh.sh new file mode 100644 index 0000000..13b4b47 --- /dev/null +++ b/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!" diff --git a/tutorials/30_git.sh b/tutorials/30_git.sh new file mode 100644 index 0000000..8459909 --- /dev/null +++ b/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! diff --git a/tutorials/31_usability.sh b/tutorials/31_usability.sh new file mode 100644 index 0000000..00f604a --- /dev/null +++ b/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 \ No newline at end of file