7c8a4893de
- restructure repo to chezmoi conventions (dot_ prefix, private_dot_ssh/) - add nvim config (was untracked) - encrypt restic pass.txt with age - remove stow artifacts (.stow-local-ignore, stow package dirs) - update bootstrap.sh to use chezmoi apply - remove runtime files from tracking (micro buffers, zed backup)
288 lines
9.2 KiB
Bash
288 lines
9.2 KiB
Bash
# ════════════════════════════════════════════════════════════
|
|
# Custom Functions
|
|
# ════════════════════════════════════════════════════════════
|
|
|
|
# ═══ Навигация ═════════════════════════════════════════════
|
|
|
|
# mkcd - создать директорию и перейти в неё
|
|
mkcd() {
|
|
mkdir -p "$1" && cd "$1"
|
|
}
|
|
|
|
# up - подняться на N уровней вверх
|
|
up() {
|
|
local d=""
|
|
local limit="${1:-1}"
|
|
for ((i=1; i<=limit; i++)); do
|
|
d="../$d"
|
|
done
|
|
|
|
if [[ -z "$d" ]]; then
|
|
d=..
|
|
fi
|
|
|
|
cd "$d" || return
|
|
}
|
|
|
|
# ═══ Поиск ═════════════════════════════════════════════════
|
|
|
|
# ff - быстрый поиск файлов
|
|
ff() {
|
|
if command -v fd &>/dev/null; then
|
|
fd "$@"
|
|
else
|
|
find . -iname "*$1*"
|
|
fi
|
|
}
|
|
|
|
# fh - поиск в истории команд с fzf
|
|
fh() {
|
|
if command -v fzf &>/dev/null; then
|
|
print -z $(history -n 1 | fzf --tac --no-sort)
|
|
else
|
|
history | grep "$1"
|
|
fi
|
|
}
|
|
|
|
# ═══ Файлы и директории ════════════════════════════════════
|
|
|
|
# extract - универсальная распаковка (если плагин не загружен)
|
|
if ! command -v extract &>/dev/null; then
|
|
extract() {
|
|
if [[ -f $1 ]]; then
|
|
case $1 in
|
|
*.tar.bz2) tar xjf "$1" ;;
|
|
*.tar.gz) tar xzf "$1" ;;
|
|
*.tar.xz) tar xJf "$1" ;;
|
|
*.bz2) bunzip2 "$1" ;;
|
|
*.rar) unrar x "$1" ;;
|
|
*.gz) gunzip "$1" ;;
|
|
*.tar) tar xf "$1" ;;
|
|
*.tbz2) tar xjf "$1" ;;
|
|
*.tgz) tar xzf "$1" ;;
|
|
*.zip) unzip "$1" ;;
|
|
*.Z) uncompress "$1" ;;
|
|
*.7z) 7z x "$1" ;;
|
|
*) echo "'$1' cannot be extracted via extract()" ;;
|
|
esac
|
|
else
|
|
echo "'$1' is not a valid file"
|
|
fi
|
|
}
|
|
fi
|
|
|
|
# backup - создать резервную копию файла
|
|
backup() {
|
|
if [[ -f $1 ]]; then
|
|
cp "$1"{,.backup-$(date +%Y%m%d-%H%M%S)}
|
|
echo "Backup created: $1.backup-$(date +%Y%m%d-%H%M%S)"
|
|
else
|
|
echo "File not found: $1"
|
|
fi
|
|
}
|
|
|
|
# ═══ Размер файлов ═════════════════════════════════════════
|
|
|
|
# dirsize - показать размер директории
|
|
dirsize() {
|
|
du -sh "${1:-.}" 2>/dev/null || echo "Directory not found"
|
|
}
|
|
|
|
# largest - показать N самых больших файлов в директории
|
|
largest() {
|
|
local num=${1:-10}
|
|
du -ah "${2:-.}" | sort -rh | head -n "$num"
|
|
}
|
|
|
|
# ═══ Процессы ══════════════════════════════════════════════
|
|
|
|
# psgrep - поиск процессов
|
|
psgrep() {
|
|
ps aux | grep -v grep | grep -i -e VSZ -e "$1"
|
|
}
|
|
|
|
# kill процесс по имени
|
|
killp() {
|
|
local pid
|
|
pid=$(ps aux | grep -v grep | grep "$1" | awk '{print $2}')
|
|
if [[ -n $pid ]]; then
|
|
echo "Killing process: $1 (PID: $pid)"
|
|
kill -9 "$pid"
|
|
else
|
|
echo "Process not found: $1"
|
|
fi
|
|
}
|
|
|
|
# ═══ Сеть ══════════════════════════════════════════════════
|
|
|
|
# myip - показать все IP адреса
|
|
myip() {
|
|
echo "External IP: $(curl -s ifconfig.me)"
|
|
echo "Local IPs:"
|
|
ip -4 addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v 127.0.0.1
|
|
}
|
|
|
|
# ports - показать открытые порты
|
|
openports() {
|
|
sudo netstat -tulanp | grep LISTEN
|
|
}
|
|
|
|
# ═══ Git ═══════════════════════════════════════════════════
|
|
|
|
# gitignore - скачать .gitignore для языка
|
|
gitignore() {
|
|
if [[ -z $1 ]]; then
|
|
echo "Usage: gitignore <language>"
|
|
return 1
|
|
fi
|
|
curl -sL "https://www.toptal.com/developers/gitignore/api/$1" -o .gitignore
|
|
echo ".gitignore created for: $1"
|
|
}
|
|
|
|
# gclone - клонировать репозиторий и перейти в него
|
|
gclone() {
|
|
if [[ -z $1 ]]; then
|
|
echo "Usage: gclone <repository>"
|
|
return 1
|
|
fi
|
|
|
|
local repo_name=$(basename "$1" .git)
|
|
git clone "$1" && cd "$repo_name" || return
|
|
}
|
|
|
|
# ═══ Разработка ════════════════════════════════════════════
|
|
|
|
# serve - быстрый HTTP сервер
|
|
serve() {
|
|
local port="${1:-8000}"
|
|
if command -v python3 &>/dev/null; then
|
|
echo "Starting server on http://localhost:$port"
|
|
python3 -m http.server "$port"
|
|
else
|
|
echo "Python3 not found"
|
|
fi
|
|
}
|
|
|
|
# json - форматировать JSON
|
|
json() {
|
|
if [[ -f $1 ]]; then
|
|
python3 -m json.tool "$1"
|
|
else
|
|
echo "$1" | python3 -m json.tool
|
|
fi
|
|
}
|
|
|
|
# ═══ Утилиты ═══════════════════════════════════════════════
|
|
|
|
# weather - погода для города
|
|
weather() {
|
|
local city="${1:-Moscow}"
|
|
curl -s "wttr.in/$city?format=3"
|
|
}
|
|
|
|
# Функция для монтирования облаков
|
|
mount-clouds() {
|
|
mkdir -p ~/YaDisk ~/GDrive
|
|
echo "Монтирую диски..."
|
|
|
|
# Яндекс.Диск
|
|
rclone mount yadisk: ~/YaDisk \
|
|
--vfs-cache-mode writes \
|
|
--vfs-cache-max-size 10G \
|
|
--vfs-cache-max-age 2h \
|
|
--allow-non-empty \
|
|
--daemon
|
|
|
|
# Google Drive
|
|
rclone mount gdrive: ~/GDrive \
|
|
--vfs-cache-mode writes \
|
|
--vfs-cache-max-size 10G \
|
|
--vfs-cache-max-age 2h \
|
|
--allow-non-empty \
|
|
--daemon
|
|
|
|
echo "Готово! Проверяю монтирование:"
|
|
ls ~/YaDisk >/dev/null 2>&1 && echo "✅ YaDisk смонтирован" || echo "⚠️ Ошибка монтирования YaDisk"
|
|
ls ~/GDrive >/dev/null 2>&1 && echo "✅ GDrive смонтирован" || echo "⚠️ Ошибка монтирования GDrive"
|
|
}
|
|
# Функция для размонтирования
|
|
unmount-clouds() {
|
|
echo "Отключаю диски..."
|
|
|
|
fusermount -uz ~/YaDisk 2>/dev/null && echo "✅ YaDisk отключен" || echo "⚠️ YaDisk не был примонтирован"
|
|
fusermount -uz ~/GDrive 2>/dev/null && echo "✅ GDrive отключен" || echo "⚠️ GDrive не был примонтирован"
|
|
}
|
|
|
|
|
|
SSH_PROXY_PID_FILE="/tmp/ssh_proxy.pid"
|
|
# Адрес Privoxy, который слушает HTTP и перенаправляет в SOCKS5
|
|
# 1. Запуск
|
|
sshp-start() {
|
|
if [ -f "$SSH_PROXY_PID_FILE" ] && kill -0 $(cat "$SSH_PROXY_PID_FILE") 2>/dev/null; then
|
|
echo "Ошибка: Прокси уже запущен (PID: $(cat $SSH_PROXY_PID_FILE))"
|
|
return 1
|
|
fi
|
|
|
|
# Запуск SSH в фоновом режиме
|
|
ssh -fN -D 127.0.0.1:1080 fl-vps
|
|
|
|
# Сохранение PID последнего запущенного процесса
|
|
pgrep -f "ssh -fN -D 127.0.0.1:1080 fl-vps" > "$SSH_PROXY_PID_FILE"
|
|
echo "SSH прокси (SOCKS5) запущен на 127.0.0.1:1080."
|
|
}
|
|
|
|
# 2. Остановка
|
|
sshp-stop() {
|
|
if [ -f "$SSH_PROXY_PID_FILE" ]; then
|
|
PID=$(cat "$SSH_PROXY_PID_FILE")
|
|
if kill "$PID" 2>/dev/null; then
|
|
rm -f "$SSH_PROXY_PID_FILE"
|
|
echo "SSH прокси (PID $PID) остановлен."
|
|
else
|
|
echo "Процесс $PID не найден. Очистка PID-файла..."
|
|
rm -f "$SSH_PROXY_PID_FILE"
|
|
fi
|
|
else
|
|
echo "Ошибка: Прокси не запущен."
|
|
fi
|
|
}
|
|
|
|
# 3. Статус
|
|
sshp-status() {
|
|
if [ -f "$SSH_PROXY_PID_FILE" ] && kill -0 $(cat "$SSH_PROXY_PID_FILE") 2>/dev/null; then
|
|
PID=$(cat "$SSH_PROXY_PID_FILE")
|
|
echo "Статус: РАБОТАЕТ (PID: $PID)"
|
|
# Проверка прослушивания порта
|
|
lsof -i -nP | grep "$PID" | grep LISTEN
|
|
else
|
|
echo "Статус: ОСТАНОВЛЕН"
|
|
fi
|
|
}
|
|
|
|
sshp-restart() {
|
|
sshp-stop
|
|
sleep 1
|
|
sshp-start
|
|
}
|
|
|
|
|
|
activate() {
|
|
local venv_dir=""
|
|
if [[ -d ".venv" ]]; then
|
|
venv_dir=".venv"
|
|
elif [[ -d "venv" ]]; then
|
|
venv_dir="venv"
|
|
else
|
|
for venv_dir in **/.venv **/venv; do
|
|
[[ -d "$venv_dir" ]] && break
|
|
done
|
|
fi
|
|
|
|
if [[ -n "$venv_dir" && -f "$venv_dir/bin/activate" ]]; then
|
|
source "$venv_dir/bin/activate"
|
|
else
|
|
echo "venv/.venv not found"
|
|
return 1
|
|
fi
|
|
}
|