# Functions shared by every machine. # # The fzf-based ones are the bulk of it. They are defined unconditionally: a # function that is never called costs nothing, and guarding each one would be # more noise than the guard is worth. Only the docker group is gated, because # those names are short enough to shadow something else on a machine without # docker. # Which hosts are holding the most connections open. detect-ddos() { sudo netstat -ntu | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -n } # cd into a directory picked with fzf. fdir() { local dir dir=$(find "${1:-.}" -path '*/\.*' -prune \ -o -type d -print 2> /dev/null | fzf +m) && cd "$dir" } # Pick a command out of history and put it on the command line rather than # running it, so it can still be edited. fhist() { print -z $( ([ -n "$ZSH_NAME" ] && fc -l 1 || history) | fzf +s --tac | sed -E 's/ *[0-9]*\*? *//' | sed -E 's/\\/\\\\/g') } # Kill a process picked with fzf. Non-root sees only its own processes, which # is also all it could kill. fkill() { local pid if [ "$UID" != "0" ]; then pid=$(ps -f -u "$UID" | sed 1d | fzf -m | awk '{print $2}') else pid=$(ps -ef | sed 1d | fzf -m | awk '{print $2}') fi if [ "x$pid" != "x" ]; then echo "$pid" | xargs kill -"${1:-9}" fi } # Kill tmux sessions picked with fzf. Needs zsh's =~ operator. tmuxkillf () { local sessions sessions="$(tmux ls|fzf --exit-0 --multi)" || return $? local i for i in "${(f@)sessions}" do [[ $i =~ '([^:]*):.*' ]] && { echo "Killing $match[1]" tmux kill-session -t "$match[1]" } done } # tm pick a session with fzf # tm attach to it, creating it if needed # Works from inside tmux too, where attaching would fail. tm() { [[ -n "$TMUX" ]] && change="switch-client" || change="attach-session" if [ "$1" ]; then tmux $change -t "$1" 2>/dev/null || (tmux new-session -d -s "$1" && tmux $change -t "$1"); return fi session=$(tmux list-sessions -F "#{session_name}" 2>/dev/null | fzf --exit-0) && tmux $change -t "$session" || echo "No sessions found." } # Leave yazi in the directory it was left in, rather than where it started. (( $+commands[yazi] )) && y() { local tmp="$(mktemp -t "yazi-cwd.XXXXXX")" cwd yazi "$@" --cwd-file="$tmp" IFS= read -r -d '' cwd < "$tmp" [ -n "$cwd" ] && [ "$cwd" != "$PWD" ] && builtin cd -- "$cwd" rm -f -- "$tmp" } # Docker helpers, all fzf pickers. Present on all three machines today, but # "ds" and "da" are short enough to be worth gating rather than defining blind. if (( $+commands[docker] )); then # start a stopped container and attach to it da() { local cid cid=$(docker ps -a | sed 1d | fzf -1 -q "$1" | awk '{print $1}') [ -n "$cid" ] && docker start "$cid" && docker attach "$cid" } # stop a running container ds() { local cid cid=$(docker ps | sed 1d | fzf -q "$1" | awk '{print $1}') [ -n "$cid" ] && docker stop "$cid" } # remove containers, multi-select. The single-select version that used to sit # above this one was dead code: it had the same name and was overwritten on # every shell start. drm() { docker ps -a | sed 1d | fzf -q "$1" --no-sort -m --tac | awk '{ print $1 }' | xargs -r docker rm } # remove images, multi-select drmi() { docker images | sed 1d | fzf -q "$1" --no-sort -m --tac | awk '{ print $3 }' | xargs -r docker rmi } fi # Arch package hygiene: remove orphans, but write down what was removed first # so the decision can be undone. if (( $+commands[yay] )); then yay_remove_orphans() { local backup_dir="$HOME/.config/yay" local date_str backup_file orphans date_str="$(date +%Y-%m-%d_%H-%M-%S)" backup_file="$backup_dir/remove_orph_${date_str}.bak" mkdir -p "$backup_dir" orphans=("${(@f)$(yay -Qtdq)}") if [[ ${#orphans[@]} -eq 0 || -z "${orphans[1]}" ]]; then echo "✔ Keine verwaisten Pakete gefunden." return 0 fi print -l -- "${orphans[@]}" > "$backup_file" echo "📦 Backup der verwaisten Pakete erstellt:" echo " $backup_file" echo echo "🧹 Entferne folgende Pakete:" print -l -- "${orphans[@]}" echo yay -Rns "${orphans[@]}" } yay_restore_orphans() { local backup_dir="$HOME/.config/yay" local backup_file packages selected backup_file=$(ls -1 "$backup_dir"/remove_orph_*.bak 2>/dev/null | fzf \ --prompt="Backup auswählen: " \ --height=40% \ --reverse) [[ -z "$backup_file" ]] && { echo "✖ Kein Backup ausgewählt." return 1 } packages=("${(@f)$(cat "$backup_file")}") if [[ ${#packages[@]} -eq 0 ]]; then echo "✖ Backup ist leer." return 1 fi selected=("${(@f)$(printf "%s\n" "${packages[@]}" | fzf \ --multi \ --prompt="Pakete auswählen (TAB): " \ --height=60% \ --reverse)}") [[ ${#selected[@]} -eq 0 ]] && { echo "✖ Keine Pakete ausgewählt." return 1 } echo echo "📦 Installiere folgende Pakete:" printf " - %s\n" "${selected[@]}" echo yay -S "${selected[@]}" } fi