Add server CLI tools installer for Ubuntu/Debian servers

Introduce a self-contained repo with an interactive install.sh that
provisions zsh, oh-my-zsh, aliases, bat/yazi configs, docker shortcuts,
and git-delta pager setup. Configs are adapted from dotfiles for SSH-only
servers — no desktop or neovim dependencies.

Installer supports --all, --update (git pull + re-run), and --uninstall
with backup restore. Core packages include vim (default editor), yazi via
apt, and idempotent apt installs with warnings for eza and git-delta when
repos lack them.
This commit is contained in:
2026-06-04 20:52:54 +02:00
commit 6fe8529d10
14 changed files with 1258 additions and 0 deletions

52
configs/aliases/.aliases Normal file
View File

@@ -0,0 +1,52 @@
#!/bin/bash
# shellcheck source=.functions.sh
. ~/.config/aliases/.functions.sh
### General aliases
# ll pimped with eza
alias ll="eza -lag --icons=always --group-directories-first --smart-group --time-style='+%d %b %y %H:%M'"
# du all items in folder, human readable
alias dh='du -chs *'
# yazi file manager
alias y='yazi'
# preview/find file using fzf and bat
alias pf='fzf --preview "bat --color=always {}"'
# cd to dir using fuzzy finder (fzf)
alias cdf='cd "$(find . -type d | fzf)"'
# (executed from / or /home might be slow)
next_line
# cd to file's directory
alias cdtf=cd_to_file
# mkdir & cd to it
alias mkcd=mkdir_and_cd
# grep shorthand
alias g='grep'
# python interpreter/REPL
alias py='python3'
# source ~/.config/aliases/.aliases
alias sa='source ~/.config/aliases/.aliases'
# edit aliases files ('ea h' for help)
alias ea=edit_aliases
# pack 'cwd' to tar.gz in parent with 'cwd' name
alias twd='tar -czf "../$(basename "$PWD").tar.gz" .'
# print alias description
alias h='display_alias_descriptions'
# LOCAL/CUSTOM bash aliases
# You can create custom local aliases in .local_aliases
# or .custom_aliases file for some temporary aliases
if [ -f ~/.config/aliases/.local_aliases ]; then
. ~/.config/aliases/.local_aliases
fi
if [ -f ~/.config/aliases/.custom_aliases ]; then
. ~/.config/aliases/.custom_aliases
fi
# source git aliases
if [ -f ~/.config/aliases/.git_aliases ]; then
. ~/.config/aliases/.git_aliases
fi
# source docker aliases
if [ -f ~/.config/aliases/.docker_aliases ]; then
. ~/.config/aliases/.docker_aliases
fi

View File

@@ -0,0 +1,69 @@
#!/bin/bash
docker_start_stop() {
local cname="$1"
if [ -z "$cname" ]; then
e_info "Usage: docker_toggle <container_name_or_id>"
return 1
fi
state=$(docker inspect -f '{{.State.Status}}' "$cname" 2>/dev/null)
case $state in
"running")
docker stop "$cname"
e_info "Container '$cname' stopped."
;;
"exited")
docker start "$cname"
e_info "Container '$cname' started."
;;
*)
e_err "Container '$cname' not found or not in a valid state."
return 1
;;
esac
}
docker_stop_all() {
for cont in $(docker ps -a --format {{.Names}}); do
docker stop $cont >/dev/null
e_info "Container $cont stopped."
done
}
docker_remove() {
container=$(docker rm $1)
e_info "Container $container removed."
}
docker_remove_all() {
for cont in $(docker ps -a --format {{.Names}}); do
docker rm $cont >/dev/null
e_info "Container $cont removed."
done
}
docker_remove_all_images() {
for img in $(docker image ls --format '{{.Repository}}:{{.Tag}}'); do
docker image rm $img >/dev/null
e_info "Image $img removed."
done
}
### Docker aliases
# show docker containers
alias da='docker ps -a'
# start or stop docker <container>
alias ds=docker_start_stop
# stop all docker containers
alias dsa=docker_stop_all
# remove docker <container>
alias dr=docker_remove
# remove all docker containers
alias dra=docker_remove_all
# list docker images in 'repo:tag'
alias dia='docker image ls --format {{.Repository}}:{{.Tag}}'
# remove docker <image>
alias dri='docker image rm'
# remove all docker images
alias dria=docker_remove_all_images

View File

@@ -0,0 +1,136 @@
#!/bin/bash
e_err() {
echo -e "\e[1;31m$1\e[0m"
}
e_info() {
echo -e "\e[1;34m$1\e[0m"
}
e_succ() {
echo -e "\e[1;32m$1\e[0m"
}
e_warn() {
echo -e "\e[1;38;5;208m$1\e[0m"
}
function fake_alias() {
:
}
function next_line() {
:
}
# FILL LINE FUNCTIONS
fill_line_with_string() {
local string="$1"
local length="$2"
local fill="${3:- }"
if [[ ${#fill} -eq 1 ]]; then
beg_char=$fill
end_char=$fill
fi
if [[ ${#fill} -eq 2 ]]; then
beg_char="${fill:0:1}"
end_char="${fill:1:1}"
fi
if [[ ${#fill} -gt 2 ]]; then
beg_char="${fill:0:1}"
end_char="${fill:0:1}"
fi
local padding=$(((length - ${#string} - 2) / 2))
local beg
beg=$(printf "%${padding}s" | tr ' ' "$beg_char")
local end
end=$(printf "%${padding}s" | tr ' ' "$end_char")
printf "%s%s%s" "$beg" " $string " "$end"
echo ""
}
fill_line() {
local length="$1"
local fill="$2"
printf "%*s\n" "$length" "" | tr ' ' "$fill"
}
# ALIAS DESCRIPTIONS
line_length=59
get_alias_descriptions() {
local file_path="$1"
if [ -f "$file_path" ]; then
echo ""
echo "@ $file_path"
local description=""
while IFS= read -r line; do
if [[ "$line" =~ ^### ]]; then
fill_line_with_string "${line#'### '}" "$line_length" "-"
elif [[ "$line" =~ ^# ]]; then
description="${line#"# "}"
elif [[ "$line" =~ ^(alias|fake_alias) ]]; then
alias_name=$(printf "%10s" "$(echo "$line" | cut -d'=' -f1 | awk '{print $2}')")
echo "$alias_name :: $description"
elif [[ $line == "next_line" ]]; then
printf "%*s%s\n" "14" "" "$description"
else
description=""
fi
done <"$file_path"
fi
}
display_alias_descriptions() {
echo ""
fill_line_with_string "ALIASES DESCRIPTIONS" "$line_length" " "
get_alias_descriptions "$ALIASES"/.aliases
get_alias_descriptions "$ALIASES"/.git_aliases
get_alias_descriptions "$ALIASES"/.docker_aliases
get_alias_descriptions "$ALIASES"/.local_aliases
get_alias_descriptions "$ALIASES"/.custom_aliases
fill_line "$line_length" "-"
}
ea_help() {
e_info "Usage: ea [c|l|h]"
echo "Edit ~/.config/aliases/.aliases file when used without arguments"
echo "Args: c :: edit ~/.config/aliases/.custom_aliases"
echo " l :: edit ~/.config/aliases/.local_aliases"
echo " f edit ~/.config/aliases/.functions.sh"
echo " h :: print help"
}
edit_aliases() {
if [ $# -eq 0 ]; then
${EDITOR:-nano} "$ALIASES"/.aliases
elif [ $# -gt 1 ]; then
e_err "Too many arguments!"
ea_help
else
case "$1" in
l) ${EDITOR:-nano} "$ALIASES"/.local_aliases ;;
c) ${EDITOR:-nano} "$ALIASES"/.custom_aliases ;;
f) ${EDITOR:-nano} "$ALIASES"/.functions.sh ;;
h) ea_help ;;
*) e_err "Invalid option!"; ea_help ;;
esac
fi
}
cd_to_file() {
cwd=$(pwd)
cd "${1:-.}" || return
file=$(fzf --preview 'bat --color=always {}')
if [ -z "$file" ]; then
cd "$cwd" || return
else
cd "$(dirname "$file")" || return
fi
}
mkdir_and_cd() {
mkdir -p "$1" || e_err "Failed to create directory: $1"
cd "$1" || e_err "Failed to navigate to directory: $1"
}

View File

@@ -0,0 +1,179 @@
#!/bin/bash
# GIT FUNCTIONS
# git checkout with tab completion
# bash override for zsh gco alias
if [ -n "$BASH_VERSION" ] && [ -f ~/.config/aliases/.git_bash_autocomplete ]; then
. ~/.config/aliases/.git_bash_autocomplete
fi
# git create stast with message
git_stash_msg() {
if [ -z "$1" ]; then
e_warn "Stash changes with message! Don't be lazy..."
else
local msg="$*"
git stash -m "$msg"
e_succ "Succesfully stashed changes as '$msg' on branch '$(git branch --show-current)'."
fi
}
# git apply stash by number
git_apply_stash() {
if [ $# -eq 0 ]; then
e_warn "Please specify stash number!"
return 1
elif [ $# -gt 1 ]; then
e_warn "Please specify only one stash number!"
return 1
else
git stash apply stash@"{$1}"
fi
}
# git echo stasth diff by number
# useful combined with '| xc'
git_stash_patch() {
if [ $# -eq 0 ]; then
e_warn "Please specify a stash number!"
return 1
elif [ $# -gt 1 ]; then
e_warn "Please specify only one stash number!"
return 1
else
git stash show -p stash@"{$1}"
fi
}
# drop stash by number with confirmation
# I accidentally dropped stashes, because I mix up gsp and gsd
git_stash_drop() {
if [ $# -eq 0 ]; then
e_warn "Please specify a stash number!"
return 1
elif [ $# -gt 1 ]; then
e_warn "Please specify only one stash number!"
return 1
else
printf "Are you sure you want to drop stash #$1? (Y/N): "
read -r confirm
if [[ "$confirm" =~ ^[yY]$ ]]; then
git stash drop stash@"{$1}"
e_info "Stash #$1 dropped."
else
e_warn "Aborted. Stash #$1 not dropped."
fi
return 0
fi
}
# git diff with optional filename from git diff --names-only | nl
git_diff_numbered() {
local files file
files=()
while IFS= read -r line; do
files+=("$line")
done < <(git diff --name-only)
if [ $# -eq 0 ]; then
printf "%s\n" "${files[@]}" | nl
elif [ $# -eq 1 ] && [[ $1 =~ ^[0-9]+$ ]]; then
if [ -n "$BASH_VERSION" ]; then
file="${files[$1 - 1]}"
else
file="${files[$1]}"
fi
[ -n "$file" ] && git diff "$file"
else
e_err "Invalid argument! Provide number from the output of 'gdn'."
fi
}
# git restore file based on the number from git diff --names-only | nl
git_restore_by_number() {
local files file
files=()
while IFS= read -r line; do
files+=("$line")
done < <(git diff --name-only)
if [ $# -eq 0 ]; then
e_err "Missing argument! Provide number from the output of 'gdn'."
elif [ $# -eq 1 ] && [[ $1 =~ ^[0-9]+$ ]]; then
if [ -n "$BASH_VERSION" ]; then
file="${files[$1 - 1]}"
else
file="${files[$1]}"
fi
[ -n "$file" ] && git restore "$file"
else
e_err "Invalid argument! Provide number from the output of 'gdn'."
fi
}
# git add untracked files, commit and push
git_commit_push() {
if [ -z "$1" ]; then
e_err "No commit message provided!"
return 1
else
local message="$*"
git add -u
git commit -m "$message"
git push
e_succ -e "\nCommit '$message' succesfully pushed to branch: '$(git branch --show-current)'."
fi
}
# git list stashes
git_stash_list() {
printf "%s\n" "$(git stash list)"
}
### Git aliases
# git status
fake_alias gst
if [ -n "$BASH_VERSION" ]; then
alias gst='git status'
fi
# git fetch all
fake_alias gfa
if [ -n "$BASH_VERSION" ]; then
alias gfa='git fetch --all --prune'
fi
# git diff
fake_alias gd
if [ -n "$BASH_VERSION" ]; then
alias gd='git diff'
fi
# git diff classic with less pager
alias gdc="git -c core.pager='less' diff"
# git diff numbered
alias gdn=git_diff_numbered
# (with filenum works only in repo root)
next_line
# git commit and push with message
alias gcpm=git_commit_push
# git checkout with tab completion
fake_alias gco
# git submodule update
fake_alias gsu
if [ -n "$BASH_VERSION" ]; then
alias gsu='git submodule update'
fi
# git stash with message
alias gstm=git_stash_msg
# git stash list
alias gstl=git_stash_list
# git stash patch <#>
alias gstp=git_stash_patch
# git stash apply <#>
alias gsta=git_apply_stash
# gti stash drop <#>
alias gstd=git_stash_drop
# git restore
alias grs='git restore'
# git restore by number from gdn
alias grsn=git_restore_by_number
# run pre-commit on changed files only
alias pc='pre-commit run --files $(git diff --name-only)'

View File

@@ -0,0 +1,11 @@
gco() {
git checkout "$@"
}
# Enable git completion if available
if [ -f /usr/share/bash-completion/completions/git ]; then
. /usr/share/bash-completion/completions/git
fi
# Enable git branch completion for gc
if type __git_complete &>/dev/null; then
__git_complete gco _git_checkout
fi