feat(bin): update scripts to function format

This commit is contained in:
2024-07-23 03:45:22 +03:00
parent 4e4692321b
commit 26f6024292
23 changed files with 1038 additions and 414 deletions

View File

@@ -352,10 +352,12 @@ section_docs()
MENU=( MENU=(
"tmux:Update tmux keybindings documentation" "tmux:Update tmux keybindings documentation"
"nvim:Update nvim keybindings documentation"
) )
case "$1" in case "$1" in
tmux) bash "$DOTFILES/local/bin/x-dfm-docs-xterm-keybindings" ;; tmux) bash "$DOTFILES/local/bin/x-dfm-docs-xterm-keybindings" ;;
nvim) bash "$DOTFILES/scripts/create-nvim-keymaps.sh" ;;
*) menu_usage "$USAGE_PREFIX" "${MENU[@]}" ;; *) menu_usage "$USAGE_PREFIX" "${MENU[@]}" ;;
esac esac
} }

View File

@@ -19,20 +19,28 @@
# Default dir to check, can be overridden in env (.bashrc, .zshrc, ...) # Default dir to check, can be overridden in env (.bashrc, .zshrc, ...)
: "${GIT_DIRTY_DIR:=$HOME/Code}" : "${GIT_DIRTY_DIR:=$HOME/Code}"
# If user has provided folder as a first argument, use it. # Enable verbosity with VERBOSE=1
if [ "$1" != "" ]; then VERBOSE="${VERBOSE:-0}"
GIT_DIRTY_DIR="$1"
fi
# UTF-8 ftw # UTF-8 ftw
GITDIRTY="❌ " GITDIRTY="❌ "
GITCLEAN="✅ " GITCLEAN="✅ "
# Function to print messages if VERBOSE is enabled
# $1 - message (string)
msg()
{
[ "$VERBOSE" -eq 1 ] && echo "$1"
}
# Function to handle errors
catch() catch()
{ {
echo "Error $1 occurred on $2" echo "Error $1 occurred on $2"
} }
# Function to check the git status of a directory
# $1 - directory (string)
gitdirty() gitdirty()
{ {
local d="$1" local d="$1"
@@ -40,13 +48,13 @@ gitdirty()
if [[ -d "$d" ]]; then if [[ -d "$d" ]]; then
if [[ -e "$d/.ignore" ]]; then if [[ -e "$d/.ignore" ]]; then
echo -e "" msg "Skipping ignored directory: $d"
else else
# Check that $d is not '--', 'vendor', or 'node_modules' # Check that $d is not '--', 'vendor', or 'node_modules'
if [[ "${d:0:2}" == "--" ]] || [[ "$d" == "vendor" ]] || [[ "$d" == "node_modules" ]]; then if [[ "${d:0:2}" == "--" ]] || [[ "$d" == "vendor" ]] || [[ "$d" == "node_modules" ]]; then
echo "" msg "Skipping excluded directory: $d"
else else
cd "$d" cd "$d" || exit
# If we have `.git` folder, check it. # If we have `.git` folder, check it.
if [[ -d ".git" ]]; then if [[ -d ".git" ]]; then
@@ -60,12 +68,14 @@ gitdirty()
# If it wasn't git repository, check subdirectories. # If it wasn't git repository, check subdirectories.
gitdirtyrepos ./* gitdirtyrepos ./*
fi fi
cd - > /dev/null || exit
fi fi
cd .. > /dev/null
fi fi
fi fi
} }
# Function to check git status for multiple directories
# $@ - directories
gitdirtyrepos() gitdirtyrepos()
{ {
for x in "$@"; do for x in "$@"; do
@@ -73,10 +83,20 @@ gitdirtyrepos()
done done
} }
set -e # Main function
trap 'case $? in main()
139) echo "segfault occurred";; {
11) echo "ssegfault occurred";; # If user has provided folder as a first argument, use it.
esac' EXIT if [ "${1:-}" != "" ]; then
GIT_DIRTY_DIR="$1"
fi
gitdirtyrepos "$GIT_DIRTY_DIR" trap 'case $? in
139) echo "segfault occurred";;
11) echo "segfault occurred";;
esac' EXIT
gitdirtyrepos "$GIT_DIRTY_DIR"
}
main "$@"

View File

@@ -6,18 +6,46 @@
# Copyright 2023 Ismo Vuorinen. All Rights Reserved. # Copyright 2023 Ismo Vuorinen. All Rights Reserved.
# License: MIT <https://opensource.org/license/mit/> # License: MIT <https://opensource.org/license/mit/>
STARTING_PATH=${1:-$(pwd)} set -euo pipefail
DIRS=$(find "$STARTING_PATH" -mindepth 1 -maxdepth 1 -type d) # Enable verbosity with VERBOSE=1
VERBOSE="${VERBOSE:-0}"
for DIR in $DIRS; do # Function to print messages if VERBOSE is enabled
echo "-> Processing dir: $DIR" # $1 - message (string)
cd "$DIR" || exit 1 msg()
if [ -d "$DIR/.git" ]; then {
git fsck --no-dangling --full --no-progress [ "$VERBOSE" -eq 1 ] && echo "$1"
echo "" }
fi
done
echo "" # Function to perform git fsck on a repository
echo "Done." # $1 - directory (string)
fsck_repo()
{
local dir=$1
msg "Processing dir: $dir"
(
cd "$dir" || exit 1
if [ -d ".git" ]; then
git fsck --no-dangling --full --no-progress
echo ""
fi
)
}
# Main function
main()
{
local starting_path=${1:-$(pwd)}
local dirs
dirs=$(find "$starting_path" -mindepth 1 -maxdepth 1 -type d)
for dir in $dirs; do
fsck_repo "$dir"
done
echo ""
echo "Done."
}
main "$@"

View File

@@ -8,7 +8,39 @@
# Copyright (c) 2023 Ismo Vuorinen. All Rights Reserved. # Copyright (c) 2023 Ismo Vuorinen. All Rights Reserved.
# License: MIT <https://opensource.org/license/mit/> # License: MIT <https://opensource.org/license/mit/>
for f in */; do (cd "$f" && echo "-> $f" && git pull --rebase --autostash --prune); done set -euo pipefail
echo "Done." # Enable verbosity with VERBOSE=1
echo "" VERBOSE="${VERBOSE:-0}"
# Function to print messages if VERBOSE is enabled
# $1 - message (string)
msg()
{
[ "$VERBOSE" -eq 1 ] && echo "$1"
}
# Function to update a git repository
# $1 - directory (string)
update_repo()
{
local dir=$1
(
cd "$dir" || exit
msg "Updating $dir"
git pull --rebase --autostash --prune
)
}
# Main function to update all subfolder git repositories
main()
{
for dir in */; do
update_repo "$dir"
done
echo "Done."
echo ""
}
main "$@"

View File

@@ -3,33 +3,84 @@
# Backup a folder with a timestamp # Backup a folder with a timestamp
# Usage: x-backup-folder folder_to_backup [filename] # Usage: x-backup-folder folder_to_backup [filename]
# If filename is not provided, folder_to_backup will be used # If filename is not provided, folder_to_backup will be used
#
# Example: x-backup-folder ~/Documents/MyFolder # Example: x-backup-folder ~/Documents/MyFolder
# #
# Copyright (c) 2022 Ismo Vuorinen. All Rights Reserved. # Copyright (c) 2022 Ismo Vuorinen. All Rights Reserved.
# Licensed under the MIT license. # Licensed under the MIT license.
DIRECTORY=$1 set -euo pipefail
FILENAME=$2
if [ -z "${DIRECTORY}" ]; then # Enable verbosity with VERBOSE=1
echo "DIRECTORY (first argument) is missing" VERBOSE="${VERBOSE:-0}"
echo "Usage: $0 folder_to_backup"
exit
fi
if [ -z "${FILENAME}" ]; then # Function to print usage information
FILENAME=$DIRECTORY usage()
fi {
echo "Usage: $0 folder_to_backup [filename]"
exit 1
}
FILENAME=$( # Function to print messages if VERBOSE is enabled
${FILENAME} \ # $1 - message (string)
| tr '/' _ \ msg()
| iconv -t ascii//TRANSLIT \ {
| sed -r s/[^a-zA-Z0-9]+/_/g \ [[ "$VERBOSE" -eq 1 ]] && echo "$1"
| sed -r s/^_+\|-+$//g }
)
TIMESTAMP=$(date "+%Y%m%d_%H%M%S") # Function to print error messages and exit
FILENAME_TIMESTAMP="${FILENAME}_${TIMESTAMP}" # $1 - error message (string)
msg_err()
{
echo "(!) ERROR: $1" >&2
exit 1
}
tar cvzf "${FILENAME_TIMESTAMP}.tar.gz" "${DIRECTORY}/" # Function to sanitize the filename
# $1 - filename (string)
sanitize_filename()
{
local filename=$1
echo "$filename" | tr '/' '_' | iconv -t ascii//TRANSLIT | sed -r 's/[^a-zA-Z0-9]+/_/g' | sed -r 's/^_+|_+$//g'
}
# Function to backup the directory
# $1 - directory to backup (string)
# $2 - filename prefix (string)
backup_directory()
{
local directory=$1
local filename=$2
local sanitized_filename
sanitized_filename=$(sanitize_filename "$filename")
local timestamp
timestamp=$(date "+%Y%m%d_%H%M%S")
local filename_timestamp="${sanitized_filename}_${timestamp}"
msg "Backing up directory '$directory' to '${filename_timestamp}.tar.gz'"
tar cvzf "${filename_timestamp}.tar.gz" "${directory}/"
msg "Backup completed and saved to '${filename_timestamp}.tar.gz'"
}
# Main function
main()
{
if [ "$#" -lt 1 ] || [ "$#" -gt 2 ]; then
usage
fi
local directory=$1
local filename=${2:-$directory}
if [ -z "$directory" ]; then
msg_err "DIRECTORY (first argument) is missing"
fi
backup_directory "$directory" "$filename"
}
main "$@"

View File

@@ -1,43 +1,91 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# #
# Backup local MySQL Database tables with certain prefix. # Backup local MySQL Database tables with a certain prefix.
# Ismo Vuorinen <https://github.com/ivuorinen> 2018 # Ismo Vuorinen <https://github.com/ivuorinen> 2018
# License: MIT # License: MIT
SCRIPT=$(basename "$0") set -euo pipefail
PREFIX=$1
FILENAME=$2
DATABASE=$3
: "${VERBOSE:=0}" # Enable verbosity with VERBOSE=1
: "${DEFAULT_DATABASE:="wordpress"}" VERBOSE="${VERBOSE:-0}"
# Default database
DEFAULT_DATABASE="wordpress"
if [ -z "${PREFIX}" ]; then # Function to print usage information
echo "(!) TABLE_PREFIX (first argument) is missing" usage()
{
echo "(>) Usage: $SCRIPT <TABLE_PREFIX> <FILENAME_PREFIX> [<DATABASE>]" echo "(>) Usage: $SCRIPT <TABLE_PREFIX> <FILENAME_PREFIX> [<DATABASE>]"
echo " * <TABLE_PREFIX> = database table prefix, e.g. 'wp_'" echo " * <TABLE_PREFIX> = database table prefix, e.g. 'wp_'"
echo " * <FILENAME_PREFIX> = FILENAME prefix, defaults to table prefix. Use something descriptive e.g. 'wordpress'" echo " * <FILENAME_PREFIX> = FILENAME prefix, defaults to table prefix. Use something descriptive e.g. 'wordpress'"
echo " * <DATABASE> = [optional] Third argument DATABASE, defaults to '$DEFAULT_DATABASE'." echo " * <DATABASE> = [optional] Third argument DATABASE, defaults to '$DEFAULT_DATABASE'."
exit 0 exit 1
fi }
if [ -z "${FILENAME}" ]; then # Function to print messages if VERBOSE is enabled
# echo "FILENAME (second argument) is missing, using PREFIX ($PREFIX)" # $1 - message (string)
FILENAME=$PREFIX msg()
fi {
[[ "$VERBOSE" -eq 1 ]] && echo "$1"
}
if [ -z "${DATABASE}" ]; then # Function to print error messages and exit
# echo "DATABASE (third argument) is missing, using default ($DEFAULT_DATABASE)" # $1 - error message (string)
DATABASE=$DEFAULT_DATABASE msg_err()
fi {
echo "(!) ERROR: $1" >&2
exit 1
}
TIMESTAMP=$(date "+%Y%m%d_%H%M%S") # Function to backup MySQL tables with a certain prefix
FILENAME_TIMESTAMP="${DATABASE}_${FILENAME}_${TIMESTAMP}.sql" # $1 - table prefix (string)
# $2 - filename prefix (string)
# $3 - database name (string)
backup_mysql_tables()
{
local prefix=$1
local filename=$2
local database=$3
mysqldump \ local timestamp
"${DATABASE}" \ timestamp=$(date "+%Y%m%d_%H%M%S")
"$( local filename_timestamp="${database}_${filename}_${timestamp}.sql"
echo "show tables like '${PREFIX}%';" \
| mysql "${DATABASE}" \ msg "Backing up tables with prefix '$prefix' from database '$database' to file '$filename_timestamp'"
| sed '/Tables_in/d'
)" > "${FILENAME_TIMESTAMP}" mysqldump \
"${database}" \
"$(
echo "show tables like '${prefix}%';" \
| mysql "${database}" \
| sed '/Tables_in/d'
)" > "${filename_timestamp}"
msg "Backup completed and saved to '$filename_timestamp'"
}
# Main function
main()
{
if [ "$#" -lt 2 ] || [ "$#" -gt 3 ]; then
usage
fi
local prefix=$1
local filename=$2
local database=${3:-$DEFAULT_DATABASE}
if [ -z "$prefix" ]; then
msg_err "TABLE_PREFIX (first argument) is missing"
fi
if [ -z "$filename" ]; then
filename=$prefix
fi
backup_mysql_tables "$prefix" "$filename" "$database"
}
# Script name for usage information
SCRIPT=$(basename "$0")
main "$@"

View File

@@ -1,19 +1,66 @@
#!/usr/bin/env bash #!/usr/bin/env bash
#
# Adapted from https://gist.github.com/xqm32/17777d035930d622d0ff7530bfab61fd # Adapted from https://gist.github.com/xqm32/17777d035930d622d0ff7530bfab61fd
# #
set -euo pipefail
# Enable verbosity with VERBOSE=1
VERBOSE="${VERBOSE:-0}"
A_DIR="$HOME/.config/alacritty" A_DIR="$HOME/.config/alacritty"
set_alacritty_theme() { # Function to print usage information
cp -f "$A_DIR/theme-$1.toml" "$A_DIR/theme-active.toml" usage()
{
echo "Usage: $0 <theme>"
echo "Available themes: dark, night, day"
exit 1
} }
ALACRITTY_THEME=$1
if [ "$ALACRITTY_THEME" = "dark" ] || [ "$ALACRITTY_THEME" = "night" ]; then
set_alacritty_theme "night"
else
set_alacritty_theme "day"
fi
# Notify alacritty about the changes # Function to print messages if VERBOSE is enabled
touch "$A_DIR/alacritty.toml" # $1 - message (string)
msg()
{
[[ "$VERBOSE" -eq 1 ]] && echo "$1"
}
# Function to set the alacritty theme
# $1 - theme (string)
set_alacritty_theme()
{
local theme=$1
msg "Setting alacritty theme to $theme"
cp -f "$A_DIR/theme-$theme.toml" "$A_DIR/theme-active.toml"
}
# Function to notify alacritty about the changes
notify_alacritty()
{
msg "Notifying alacritty about the changes"
touch "$A_DIR/alacritty.toml"
}
# Main function
main()
{
if [ "$#" -ne 1 ]; then
usage
fi
local alacritty_theme=$1
case "$alacritty_theme" in
day)
set_alacritty_theme "day"
;;
*)
set_alacritty_theme "night"
;;
esac
notify_alacritty
msg "Theme set successfully!"
}
main "$@"

View File

@@ -1,19 +1,41 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# #
# Check git repo's files .gitattributes and are all of them mapped. # Check git repo's files .gitattributes and ensure all of them are mapped.
# Ismo Vuorinen <https://github.com/ivuorinen> 2022 # Ismo Vuorinen <https://github.com/ivuorinen> 2022
# source "${DOTFILES}/config/shared.sh"
if ! command -v git &> /dev/null; then set -euo pipefail
echo "git could not be found, please install it first"
exit 1
fi
missing_attributes=$(git ls-files | git check-attr -a --stdin | grep "text: auto") # Enable verbosity with VERBOSE=1
VERBOSE="${VERBOSE:-0}"
if [[ "$missing_attributes" ]]; then # Function to check if git is installed
echo ".gitattributes rule missing for the following files:" check_git_installed()
echo "$missing_attributes" {
else if ! command -v git &> /dev/null; then
echo "All files have a corresponding rule in .gitattributes" msg_err "git could not be found, please install it first"
fi fi
}
# Function to check for missing .gitattributes
check_gitattributes()
{
local missing_attributes
missing_attributes=$(git ls-files | git check-attr -a --stdin | grep "text: auto" || true)
if [[ -n "$missing_attributes" ]]; then
echo ".gitattributes rule missing for the following files:"
echo "$missing_attributes"
else
echo "All files have a corresponding rule in .gitattributes"
fi
}
# Main function
main()
{
check_git_installed
check_gitattributes
}
main "$@"

View File

@@ -4,13 +4,49 @@
# Copyright (c) 2023 Ismo Vuorinen. All Rights Reserved. # Copyright (c) 2023 Ismo Vuorinen. All Rights Reserved.
# Licensed under MIT License. http://www.opensource.org/licenses/mit-license. # Licensed under MIT License. http://www.opensource.org/licenses/mit-license.
dir="$1" # Enable verbosity with VERBOSE=1
VERBOSE="${VERBOSE:-0}"
[ $# -eq 0 ] && { # Function to print usage information
usage()
{
echo "Usage: $0 full/path/to/dir/to/create" echo "Usage: $0 full/path/to/dir/to/create"
exit 1 exit 1
} }
if [ ! -d "$dir" ]; then # Function to print messages if VERBOSE is enabled
mkdir -p "$dir" && exit 0 # $1 - message (string)
fi msg()
{
[[ "$VERBOSE" -eq 1 ]] && echo "$1"
return 0
}
# Function to create a directory if it doesn't exist
# $1 - directory to create (string)
create_directory()
{
local dir=$1
if [ ! -d "$dir" ]; then
msg "Creating directory: $dir"
mkdir -p "$dir"
msg "Directory created: $dir"
else
msg "Directory already exists: $dir"
fi
return 0
}
# Main function
main()
{
if [ "$#" -ne 1 ]; then
usage
fi
create_directory "$1"
exit 0
}
main "$@"

View File

@@ -2,24 +2,48 @@
# #
# x-xterm-update-keybindings # x-xterm-update-keybindings
# Updates $HOME/.dotfiles/docs/tmux.md with my keybindings. # Updates $HOME/.dotfiles/docs/tmux.md with my keybindings.
# Usage: x-xterm-update-keybindings
# Author: Ismo Vuorinen <https://github.com/ivuorinen> 2024
# shellcheck source=./../../config/shared.sh
source "${DOTFILES}/config/shared.sh"
# shellcheck source=./../../scripts/shared.sh # Enable verbosity with VERBOSE=1
source "$HOME/.dotfiles/scripts/shared.sh" VERBOSE="${VERBOSE:-0}"
x-have tmux || { # Check if tmux is installed
msg_err "tmux not found" && exit 0 check_tmux_installed()
{
if ! x-have tmux; then
msg_err "tmux not found"
fi
} }
TMUX_KEYBINDINGS_DOCS="$DOTFILES/docs/tmux-keybindings.md" # Generate tmux keybindings documentation
generate_tmux_keybindings()
{
local tmux_keybindings_docs="$1"
CB="\n\`\`\`\n" local cb="\n\`\`\`\n"
KB=$(tmux lsk -Tprefix -N | sed -e 's/^/ /;') local kb
H="# tmux keybindings\n" kb=$(tmux lsk -Tprefix -N | sed -e 's/^/ /;')
L="\nLeader: \`<ctrl><space>\`\n" local h="# tmux keybindings\n"
local l="\nLeader: \`<ctrl><space>\`\n"
# Generalize expanded $HOME to "$HOME" # Generalize expanded $HOME to "$HOME"
KB="${KB//$HOME/\$HOME}" kb="${kb//$HOME/\$HOME}"
msg "Outputting tmux keybindings to $TMUX_KEYBINDINGS_DOCS" msg "Outputting tmux keybindings to $tmux_keybindings_docs"
echo -e "${H}${L}${CB}${KB}${CB}" > "$TMUX_KEYBINDINGS_DOCS" echo -e "${h}${l}${cb}${kb}${cb}" > "$tmux_keybindings_docs"
msg_done "Done!" msg "Done!"
}
# Main function
main()
{
check_tmux_installed
local tmux_keybindings_docs="$DOTFILES/docs/tmux-keybindings.md"
generate_tmux_keybindings "$tmux_keybindings_docs"
}
main "$@"

View File

@@ -1,17 +1,102 @@
#!/usr/bin/env bash #!/usr/bin/env bash
#
# Fetch the latest release version of a GitHub repository in tar.gz format (e.g. v1.0.0.tar.gz)
# Usage: x-gh-get-latest-release-targ <repo> [--get]
# Author: Ismo Vuorinen <https://github.com/ivuorinen> 2024
REPO=$1 set -euo pipefail
if [ -z "$REPO" ]; then # Enable verbosity with VERBOSE=1
echo "Usage: $0 <repo> (e.g. ivuorinen/dotfiles)" VERBOSE="${VERBOSE:-0}"
# Function to print usage information
usage()
{
echo "Usage: $0 <github repo> [--get] (e.g. ivuorinen/dotfiles)"
echo " --get: Download and extract the tarball"
exit 1 exit 1
fi }
LOCATION=$(curl -s "https://api.github.com/repos/${REPO}/releases/latest" \ # Function to print messages if VERBOSE is enabled
| sed -Ene '/^[[:blank:]]+"tarball_url":[[:blank:]]"(https:[^"]+)",/s//\1/p') # $1 - message (string)
msg()
{
[[ "$VERBOSE" -eq 1 ]] && echo "$1"
return 0
}
echo "Downloading and extracting from: $LOCATION" # Function to fetch the tarball URL of the latest release from GitHub
# $1 - GitHub repository (string)
get_latest_tarball_url()
{
local repo=$1
curl --location --silent "$LOCATION" | tar --extract --gzip --file=- local tarball_url
tarball_url=$(curl -s "https://api.github.com/repos/${repo}/releases/latest" \
| sed -Ene '/^[[:blank:]]+"tarball_url":[[:blank:]]"(https:[^"]+)",/s//\1/p')
if [ -z "$tarball_url" ]; then
echo "(!) Failed to fetch the tarball URL for repository: $repo"
exit 1
fi
echo "$tarball_url"
return 0
}
# Function to download and extract the tarball
# $1 - tarball URL (string)
download_and_extract()
{
local url="$1"
msg "Downloading and extracting from: $url"
curl --location --silent "$url" | tar --extract --gzip --file=- || {
echo "(!) Failed to download or extract the tarball."
exit 1
}
return 0
}
# Main function
main()
{
if [ "$#" -lt 1 ] || [ "$#" -gt 2 ]; then
usage
fi
local repo=$1
local get_tarball=false
if [ "$#" -eq 2 ]; then
# Check if the first or second argument is --get
if [ "$1" == "--get" ] || [ "$2" == "--get" ]; then
get_tarball=true
else
usage
fi
fi
# Check if the first argument is --get
if [ "$1" == "--get" ]; then
repo="$2"
fi
msg "Fetching the tarball URL for the latest release of repository: $repo"
local location
location=$(get_latest_tarball_url "$repo")
if $get_tarball; then
download_and_extract "$location"
else
echo "$location"
fi
return 0
}
main "$@"
# vim: set ts=2 sw=2 ft=sh et: # vim: set ts=2 sw=2 ft=sh et:

View File

@@ -1,18 +1,68 @@
#!/usr/bin/env bash #!/usr/bin/env bash
#
# Get latest release version from GitHub
# Usage: x-gh-get-latest-version <repo>
# Author: Ismo Vuorinen <https://github.com/ivuorinen> 2024
REPO=$1 set -euo pipefail
if [ -z "$REPO" ]; then # Enable verbosity with VERBOSE=1
VERBOSE="${VERBOSE:-0}"
# Function to print usage information
usage()
{
echo "Usage: $0 <repo> (e.g. ivuorinen/dotfiles)" echo "Usage: $0 <repo> (e.g. ivuorinen/dotfiles)"
exit 1 exit 1
fi }
VERSION=$( # Function to print messages if VERBOSE is enabled
curl -s "https://api.github.com/repos/${REPO}/releases/latest" \ # $1 - message (string)
msg()
{
[[ "$VERBOSE" -eq 1 ]] && echo "$1"
return 0
}
# Function to fetch the latest release version from GitHub
# $1 - GitHub repository (string)
get_latest_release()
{
local repo=$1
local version
version=$(curl -s "https://api.github.com/repos/${repo}/releases/latest" \
| grep "tag_name" \ | grep "tag_name" \
| awk '{print substr($2, 2, length($2)-3)}' | awk -F '"' '{print $4}')
)
echo "$VERSION" if [ -z "$version" ]; then
msg "Failed to fetch the latest release version for repository: $repo"
echo ""
exit 1
fi
echo "$version"
return 0
}
# Main function
main()
{
if [ "$#" -ne 1 ]; then
usage
fi
local repo=$1
msg "Fetching the latest release version for repository: $repo"
local version
version=$(get_latest_release "$repo")
echo "$version"
return 0
}
main "$@"
# vim: set ts=2 sw=2 ft=sh et: # vim: set ts=2 sw=2 ft=sh et:

View File

@@ -1,9 +1,48 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Returns which status # Returns which status
which "$1" >&/dev/null
if [ $? -eq 0 ]; then # Enable verbosity with VERBOSE=1
exit 0 VERBOSE="${VERBOSE:-0}"
else
# Function to print usage information
usage()
{
echo "Usage: $0 <command>"
exit 1 exit 1
fi }
# Function to print messages if VERBOSE is enabled
# $1 - message (string)
msg()
{
[[ "$VERBOSE" -eq 1 ]] && echo "$1"
return 0
}
# Function to check if a command exists
# $1 - command to check (string)
check_command()
{
local cmd=$1
if command -v "$cmd" > /dev/null 2>&1; then
msg "(*) '$cmd' is available on the system."
exit 0
else
msg "(!) '$cmd' is NOT available on the system."
exit 1
fi
}
# Main function
main()
{
if [ "$#" -ne 1 ]; then
usage
fi
check_command "$1"
return 0
}
main "$@"

View File

@@ -1,4 +1,50 @@
#!/usr/bin/env bash #!/usr/bin/env bash
#
# Create a directory and cd into it # Create a directory and cd into it
# Usage: mkcd <dir>
mkdir -p "$@" && cd "$@" || exit set -euo pipefail
# Set verbosity with VERBOSE=1
VERBOSE="${VERBOSE:-0}"
# Function to print usage information
usage()
{
echo "Usage: $0 <dir>"
exit 1
}
# Function to print messages if VERBOSE is enabled
# $1 - message (string)
msg()
{
[[ "$VERBOSE" -eq 1 ]] && echo "$1"
}
# Function to create a directory and cd into it
# $1 - directory to create and cd into (string)
mkcd()
{
local dir=$1
mkdir -p "$dir" && msg "Directory $dir created"
cd "$dir" || {
msg "Failed to cd into $dir"
exit 1
}
msg "Changed directory to $dir"
}
# Main function
main()
{
if [ "$#" -ne 1 ]; then
usage
fi
mkcd "$1"
}
main "$@"

View File

@@ -6,16 +6,34 @@
# Modified by: Ismo Vuorinen <https://github.com/ivuorinen> 2020 # Modified by: Ismo Vuorinen <https://github.com/ivuorinen> 2020
# Originally from: https://www.commandlinefu.com/commands/view/8951 # Originally from: https://www.commandlinefu.com/commands/view/8951
# Original author: https://www.commandlinefu.com/commands/by/wickedcpj # Original author: https://www.commandlinefu.com/commands/by/wickedcpj
#
echo 'User: Command: PID: Port:'
echo '========================================================='
lsof -i 4 -P -n +c 0 \ set -euo pipefail
| grep -i 'listen' \
| awk '{print $3, $1, $2, $9}' \
| sed 's/ [a-z0-9\.\*]*:/ /' \
| sort -k 3 -n \
| xargs printf '%-15s %-25s %-8s %-5s\n' \
| uniq
echo "" # Function to print the header
print_header()
{
echo 'User: Command: PID: Port:'
echo '========================================================='
}
# Function to list open ports
list_open_ports()
{
lsof -i 4 -P -n +c 0 \
| grep -i 'listen' \
| awk '{print $3, $1, $2, $9}' \
| sed 's/ [a-z0-9\.\*]*:/ /' \
| sort -k 3 -n \
| xargs printf '%-15s %-25s %-8s %-5s\n' \
| uniq
}
# Main function
main()
{
print_header
list_open_ports
echo ""
}
main "$@"

View File

@@ -1,5 +1,15 @@
#!/usr/bin/env php #!/usr/bin/env php
<?php <?php
/**
* Quota usage
* Show quota usage
*
* @package x-quota-usage
* @version 1.0.0
* @link https://github.com/ivuorinen/dotfiles/blob/main/local/bin/x-quota-usage.php
* @license MIT
* @author Ismo Vuorinen <https://github.com/ivuorinen>
*/
error_reporting(E_ALL); error_reporting(E_ALL);
$debug = false; $debug = false;

View File

@@ -14,168 +14,119 @@
# pkill (coreutils) # pkill (coreutils)
# #
# 2021-2022 : João F. © BeyondMagic <koetemagie@gmail.com> # 2021-2022 : João F. © BeyondMagic <koetemagie@gmail.com>
# 2024- : Ismo Vuorinen <https://github.com/ivuorinen>
# 1. Variables. # Enable verbosity with VERBOSE=1
VERBOSE="${VERBOSE:-0}"
# Variables
frame_rate=30
name='camera'
path_recordings="$HOME/.cache/recording"
replace_id="$HOME/.cache/recording.id"
# Function to print messages if VERBOSE is enabled
# $1 - message (string)
msg()
{ {
# A. Indepedent of variables. [ "$VERBOSE" -eq 1 ] && echo "$1"
frame_rate=30
time=10
name='カメラ'
# B. Depedent of variables.
path_recordings="$HOME/.cache/recording"
icons="$HOME/.local/share/icons"
replace_id="$HOME/.cache/recording.id"
} }
# 2. Functions to minise code. # Notify function
#{
# I.
notify() notify()
{ {
notify-call --replace-file "$replace_id" "$@"
notify-call \
--replace-file "$replace_id" \
"$@"
} }
# II. # Stop recording function
stop() stop()
{ {
# A.
#pkill -INT -f 'ffmpeg -f alsa -ac 1 -i pulse -f x11grab -r 30 -s '
giph --stop giph --stop
# C.
eww update record_menu=false eww update record_menu=false
}
#}
# #. Kill previous giph process.
if [ "$(pgrep -f 'bash.+giph')" ]; then
# A. Let the user decide.
next=$(notify \
-d 'echo yes' \
"$name" \
'Do you want to stop current recording?')
# A. End with previous giph session.
[ "$next" = 'yes' ] && stop
# B. Just exit cleanly.
exit 0
fi
# 2. To see if current fyletype is supported.
{
case "$1" in
# A. Supported.
'mkv' | 'gif' | 'webm' | 'mp4') ;;
# B. Not supported.
*)
# I. Let the user decide.
format=$(notify \
-o 'echo mkv:MKV' \
-o 'echo webm:WEBM' \
-o 'echo mp4:MP4' \
-o 'echo gif:GIF' \
"$name" \
'What is the filetype you want to record?')
# II. Execute itself.
exec $0 $format $2
;;
esac
} }
# 3. Whether to choose fullscreen recording or sizeable one. # Function to check for required applications
check_dependencies()
{ {
if [ "$2" = 'fullscreen' ]; then for cmd in ffmpeg notify-send.sh pkill eww giph slop; do
if ! command -v "$cmd" &> /dev/null; then
# A. From <WxH+X+Y> monitor. echo "Required command '$cmd' not found. Please install it before running this script."
geometry="$(xrandr | awk '/ primary/{print $4}')" exit 1
fi
elif [ "$2" = 'set' ]; then done
}
# A. To get size & position of the recording set.
geometry="$(slop -f "%wx%h+%x+%y")"
else
# I. Let the user decide.
next=$(notify \
-o 'echo fullscreen:The whole_screen!' \
-o 'echo set:Let me set.' \
"$name" \
'How exactly do you want to record?')
# II. Execute itself.
exec $0 $1 $next
# Function to kill previous giph process if running
kill_previous_process()
{
if pgrep -f 'bash.+giph' > /dev/null; then
next=$(notify -d 'echo yes' "$name" 'Do you want to stop current recording?')
[ "$next" = 'yes' ] && stop
exit 0
fi fi
} }
# 4. Start recording. # Function to check if the current file type is supported
check_file_type()
{ {
case "$1" in
'mkv' | 'gif' | 'webm' | 'mp4') ;;
*)
format=$(
notify \
-o 'echo mkv:MKV' \
-o 'echo webm:WEBM' \
-o 'echo mp4:MP4' \
-o 'echo gif:GIF' \
"$name" \
'What is the filetype you want to record?'
)
exec "$0" "$format" "$2"
;;
esac
}
# Function to determine recording scope
determine_scope()
{
if [ "$2" = 'fullscreen' ]; then
geometry=$(xrandr | awk '/ primary/{print $4}')
elif [ "$2" = 'set' ]; then
geometry=$(slop -f "%wx%h+%x+%y")
else
next=$(notify -o 'echo fullscreen:The whole_screen!' -o 'echo set:Let me set.' "$name" 'How exactly do you want to record?')
exec "$0" "$1" "$next"
fi
}
# Function to start recording
start_recording()
{
mkdir -p "$path_recordings" mkdir -p "$path_recordings"
name_file="$path_recordings/$2-$(date +'%a_%b_%d_%H:%M:%S').$1" name_file="$path_recordings/$2-$(date +'%a_%b_%d_%H:%M:%S').$1"
# A. Timer.
#for i in {1..$time}; do
# # I.
# notify "Starting in $i seconds."
# # II. Wait for next second.
# sleep ${i}s
#done
# B. Send a sign of recording to lemonbar so that you know it is being recorded.
eww update record_menu=true eww update record_menu=true
# C. Start recording. giph -g "$geometry" -f "$frame_rate" "$name_file"
giph \
-g "$geometry" \
-f "$frame_rate" \
"$name_file"
# D.
stop stop
# E. responder=$(notify -o 'echo open:See file?' -o 'echo none:Hell no' "$name" 'Recording has finished.')
responder="$(notify \
-o 'echo open:See file?' \
-o 'echo none:Hell no' \
"$name" \
'Recording has finished.')"
# F. For action-driven response.
if [ "$responder" = 'open' ]; then if [ "$responder" = 'open' ]; then
nohup gtk-launch "$(xdg-mime query default inode/directory)" "$path_recordings/" > /dev/null 2>&1 &
# I.
nohup \
gtk-launch \
"$(xdg-mime query default inode/directory)" \
"$path_recordings/" \
> /dev/null 2>&1 &
fi fi
rm -f "$replace_id"
} }
rm -f "$replace_id" main()
{
check_dependencies
kill_previous_process "$@"
check_file_type "$@"
determine_scope "$@"
start_recording "$@"
}
main "$@"

View File

@@ -1,50 +1,71 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Check which php versions are installed with brew, and create aliases for each installation. # Check which PHP versions are installed with brew, and create aliases for each installation.
# Copyright (c) 2023 Ismo Vuorinen. All Rights Reserved. # Copyright (c) 2023 Ismo Vuorinen. All Rights Reserved.
set -euo pipefail set -euo pipefail
# Set verbosity with VERBOSE=1 x-load-configs # Set verbosity with VERBOSE=1 x-set-php-aliases
VERBOSE="${VERBOSE:=0}" VERBOSE="${VERBOSE:-0}"
[ "$VERBOSE" = "2" ] && { # Enable debugging if verbosity is set to 2
set -x [ "$VERBOSE" = "2" ] && set -x
}
! x-have brew && { # Check if brew is installed, if not exit.
if ! command -v brew &> /dev/null; then
exit 0 exit 0
fi
# Function to read installed PHP versions using brew
get_php_versions()
{
local versions=()
while IFS="" read -r line; do
versions+=("$line")
done < <(bkt -- brew list | grep '^php')
echo "${versions[@]}"
} }
# Get installed php versions from brew and setup aliases # Function to create aliases for each PHP version
php_versions=() create_aliases()
while IFS="" read -r line; do php_versions+=("$line"); done < <(bkt -- brew list | grep '^php') {
local php_versions=("$@")
local php_error_reporting='-d error_reporting=22527'
php_error_reporting='-d error_reporting=22527' for version in "${php_versions[@]}"; do
[ "$VERBOSE" = "1" ] && echo "Setting aliases for $version"
for version in "${php_versions[@]}"; do # Drop the dot from version (e.g., 8.0 -> 80)
[ "$VERBOSE" = "1" ] && echo "Setting aliases for $version" local php_abbr="${version//\./}"
# drop the dot from version (8.0 -> 80) # Replace "php@" with "p" so "php@80" becomes "p80"
php_abbr="${version//\./}" local php_alias="${php_abbr//php@/p}"
# replace "php@" with "p" so "php@80" becomes "p80"
php_alias="${php_abbr//php@/p}"
# Fetch the exec path once # Fetch the exec path once
php_exec="$HOMEBREW_PREFIX/opt/$version/bin/php" local php_exec="$HOMEBREW_PREFIX/opt/$version/bin/php"
[ -f "$php_exec" ] && { if [ -f "$php_exec" ]; then
[ "$VERBOSE" = "1" ] && echo "-> php_exec $php_exec" [ "$VERBOSE" = "1" ] && echo "-> php_exec $php_exec"
# Raw PHP without error_reporting flag. # Raw PHP without error_reporting flag.
# shellcheck disable=SC2139 alias "${php_alias}r"="$php_exec"
alias "${php_alias}"r="$php_exec"
# PHP with error_reporting flag. # PHP with error_reporting flag.
# shellcheck disable=SC2139,SC2140 alias "$php_alias"="$php_exec $php_error_reporting"
alias "$php_alias"="$php_exec $php_error_reporting"
# Local PHP Server. # Local PHP Server.
# shellcheck disable=SC2139,SC2140 alias "${php_alias}s"="$php_exec -S localhost:9000"
alias "${php_alias}s"="$php_exec -S localhost:9000"
# Use composer with specific PHP and error_reporting flag on. # Use composer with specific PHP and error_reporting flag on.
# shellcheck disable=SC2139,SC2140 alias "${php_alias}c"="$php_exec $php_error_reporting $(which composer)"
alias "${php_alias}c"="$php_exec $php_error_reporting $(which composer)" fi
} done
done }
# Main function
main()
{
local php_versions
php_versions=($(get_php_versions))
create_aliases "${php_versions[@]}"
}
main "$@"

View File

@@ -6,47 +6,73 @@
# Ismo Vuorinen <https://github.com/ivuorinen> 2023 # Ismo Vuorinen <https://github.com/ivuorinen> 2023
# MIT License # MIT License
set -euo pipefail
# ENV Variables # ENV Variables
: "${VERBOSE:=0}" # VERBOSE=1 x-sha256sum-matcher file1 file2 : "${VERBOSE:=0}" # VERBOSE=1 x-sha256sum-matcher file1 file2
file_1="$1" # Return sha256sum for file
file_2="$2"
# return sha256sum for file
# $1 - filename (string) # $1 - filename (string)
get_sha256sum() get_sha256sum()
{ {
sha256sum "$1" | head -c 64 sha256sum "$1" | head -c 64
} }
[ $# -eq 0 ] && { # Print message if VERBOSE is enabled
echo "Usage: $0 file1.sh file2.sh" && exit 1 # $1 - message (string)
}
msg() msg()
{ {
[[ "$VERBOSE" -eq 1 ]] && echo "$1" [[ "$VERBOSE" -eq 1 ]] && echo "$1"
} }
# Print error message and exit
# $1 - error message (string)
error() error()
{ {
msg "(!) ERROR: $1" && exit 1 msg "(!) ERROR: $1"
exit 1
} }
if [ ! -f "$file_1" ]; then # Validate input arguments
error "File 1 does not exist: $file_1" validate_inputs()
fi {
if [ "$#" -ne 2 ]; then
echo "Usage: $0 file1 file2"
exit 1
fi
}
if [ ! -f "$file_2" ]; then # Check if file exists
error "File 2 does not exist: $file_2" # $1 - filename (string)
fi check_file_exists()
{
local filename=$1
if [ ! -f "$filename" ]; then
error "File does not exist: $filename"
fi
}
file_1_hash=$(get_sha256sum "$file_1") # Main function
file_2_hash=$(get_sha256sum "$file_2") main()
{
local file_1=$1
local file_2=$2
if [ "$file_1_hash" != "$file_2_hash" ]; then validate_inputs "$file_1" "$file_2"
error "Files do not match" check_file_exists "$file_1"
else check_file_exists "$file_2"
msg "(*) Success: Files do match"
exit 0 local file_1_hash
fi local file_2_hash
file_1_hash=$(get_sha256sum "$file_1")
file_2_hash=$(get_sha256sum "$file_2")
if [ "$file_1_hash" != "$file_2_hash" ]; then
error "Files do not match"
else
msg "(*) Success: Files do match"
fi
}
main "$@"

View File

@@ -1,39 +1,69 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Generate thumbnails using magick # Generate thumbnails using ImageMagick (magick)
# https://imagemagick.org/script/download.php # https://imagemagick.org/script/download.php
# #
# Defaults to current directory creating thumbs with 1000x1000 # Defaults to current directory creating thumbnails with 1000x1000
# images with 200px white borders around the original image. # dimensions and 200px white borders around the original image.
# #
# Defaults can be overridden with ENV variables like this: # Defaults can be overridden with ENV variables like this:
# $ THMB_BACKGROUND=black x-thumbgen ~/images/ # $ THMB_BACKGROUND=black x-thumbgen ~/images/
# #
# Created by: Ismo Vuorinen <https://github.com/ivuorinen> 2015 # Created by: Ismo Vuorinen <https://github.com/ivuorinen> 2015
: "${THMB_SOURCE:=$1}" set -euo pipefail
# Default values
: "${THMB_SOURCE:=${1:-}}"
: "${THMB_BACKGROUND:=white}" : "${THMB_BACKGROUND:=white}"
: "${THMB_RESIZE:=800x800}" : "${THMB_RESIZE:=800x800}"
: "${THMB_EXTENT:=1000x1000}" : "${THMB_EXTENT:=1000x1000}"
[ $# -eq 0 ] && { # Print usage information
usage()
{
echo "Usage: $0 /full/path/to/image/folder" echo "Usage: $0 /full/path/to/image/folder"
exit 1 exit 1
} }
if [ "$THMB_SOURCE" == "" ] || [ ! -d "$THMB_SOURCE" ]; then # Check if ImageMagick is installed
THMB_SOURCE=$(pwd) check_magick_installed()
fi {
if ! command -v magick &> /dev/null; then
echo "magick not found in PATH, https://imagemagick.org/script/download.php"
exit 1
fi
}
if command -v magick &> /dev/null; then # Generate thumbnails
generate_thumbnails()
{
local source=$1
magick \ magick \
"$THMB_SOURCE/*" \ "${source}/*" \
-resize "$THMB_RESIZE" \ -resize "$THMB_RESIZE" \
-background "$THMB_BACKGROUND" \ -background "$THMB_BACKGROUND" \
-gravity center \ -gravity center \
-extent "$THMB_EXTENT" \ -extent "$THMB_EXTENT" \
-set filename:fname '%t_thumb.%e' +adjoin '%[filename:fname]' -set filename:fname '%t_thumb.%e' +adjoin '%[filename:fname]'
}
else # Main function
echo "magick not found in PATH, https://imagemagick.org/script/download.php" main()
fi {
# Validate input
if [ -z "$THMB_SOURCE" ]; then
usage
fi
# Check if the source directory is valid
if [ ! -d "$THMB_SOURCE" ]; then
echo "Invalid directory: $THMB_SOURCE"
exit 1
fi
check_magick_installed
generate_thumbnails "$THMB_SOURCE"
}
main "$@"

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
## #
# This script contains helper for sha256 validating your downloads # This script contains a helper for sha256 validating your downloads
# #
# Source: https://gist.github.com/onnimonni/b49779ebc96216771a6be3de46449fa1 # Source: https://gist.github.com/onnimonni/b49779ebc96216771a6be3de46449fa1
# Author: Onni Hakala # Author: Onni Hakala
@@ -9,44 +9,60 @@
# Updated by Ismo Vuorinen <https://github.com/ivuorinen> 2022 # Updated by Ismo Vuorinen <https://github.com/ivuorinen> 2022
## ##
if ! command -v sha256 &> /dev/null; then set -euo pipefail
echo "git could not be found, please install it first"
exit
fi
# Stop program and give error message # Stop program and give error message
# $1 - error message (string) # $1 - error message (string)
function error error()
{ {
echo "(!) ERROR: $1" echo "(!) ERROR: $1" >&2
exit 1 exit 1
} }
# return sha256sum for file # Check for sha256sum command
if ! command -v sha256sum &> /dev/null; then
error "sha256sum could not be found, please install it first"
fi
# Return sha256sum for file
# $1 - filename (string) # $1 - filename (string)
function get_sha256sum get_sha256sum()
{ {
sha256sum "$1" | head -c 64 sha256sum "$1" | head -c 64
} }
# Good variable names pls # Validate input arguments
filename=$1 validate_inputs()
file_hash=$2 {
if [ -z "${filename:-}" ]; then
error "You need to provide filename as the first parameter"
fi
# Check input if [ -z "${file_hash:-}" ]; then
if [ -z "$filename" ]; then error "You need to provide sha256sum as the second parameter"
error "You need to provide filename in first parameter" fi
fi }
if [ -z "$file_hash" ]; then # Main validation logic
error "You need to provide sha256sum in second parameter" validate_file()
fi {
if [ ! -f "$filename" ]; then
error "File $filename doesn't exist"
elif [ "$(get_sha256sum "$filename")" = "$file_hash" ]; then
echo "(*) Success: $filename matches provided sha256sum"
else
error "$filename doesn't match provided sha256sum"
fi
}
# Check if the file is valid # Main function
if [ ! -f "$filename" ]; then main()
error "File $filename doesn't exist" {
elif [ "$(get_sha256sum "$filename")" = "$file_hash" ]; then filename=$1
echo "(*) Success: $filename matches provided sha256sum" file_hash=$2
else
error "$filename doesn't match provided sha256sum" validate_inputs
fi validate_file
}
main "$@"

View File

@@ -10,23 +10,31 @@
# ./when-down 1.2.3.4 ssh 1.2.3.4 # ./when-down 1.2.3.4 ssh 1.2.3.4
# #
# # Ensure we received the correct number of arguments.
# Ensure we received the correct number of arguments. if [ "$#" -lt 2 ]; then
#
if [ $# -lt 2 ]; then
echo "Usage: $0 HOST COMMAND..." echo "Usage: $0 HOST COMMAND..."
exit 1 exit 1
fi fi
HOST=$1 wait_for_host_down()
{
local host=$1
echo "Waiting for $HOST to get down..." echo "Waiting for $host to go down..."
true while ping -c 1 -W 1 "$host" > /dev/null 2>&1; do
while [ $? -ne 1 ]; do sleep 1
ping -c 1 -W 1 "$HOST" > /dev/null done
done }
shift main()
{
local host=$1
shift
"$@" wait_for_host_down "$host"
"$@"
}
main "$@"

View File

@@ -14,32 +14,46 @@
# ./when-up ssh 1.2.3.4 # ./when-up ssh 1.2.3.4
# #
# # Ensure we received the correct number of arguments.
# Ensure we received the correct number of arguments. if [ "$#" -lt 2 ]; then
#
if [ $# -lt 2 ]; then
echo "Usage: $0 HOST COMMAND..." echo "Usage: $0 HOST COMMAND..."
exit 1 exit 1
fi fi
if [ "$1" = "ssh" ]; then get_host()
HOST=$2 {
else if [ "$1" = "ssh" ]; then
HOST=$1 echo "$2"
fi else
echo "$1"
fi
}
echo "Waiting for $HOST to come online..." wait_for_host()
{
local host=$1
ping -c 1 -W 1 "$HOST" > /dev/null echo "Waiting for $host to come online..."
while [ $? -ne 0 ]; do
sleep 1
ping -c 1 -W 1 "$HOST" > /dev/null
done
# By the time we reach here the ping-command has completed successfully while ! ping -c 1 -W 1 "$host" > /dev/null 2>&1; do
# so we can launch the command we were given - along with any arguments. sleep 1
if [ "$1" != "ssh" ]; then done
shift }
fi
"$@" main()
{
local host
host=$(get_host "$@")
wait_for_host "$host"
if [ "$1" = "ssh" ]; then
shift 1
else
shift
fi
"$@"
}
main "$@"