This commit is contained in:
2024-11-24 21:13:37 +08:00
parent 7bb8a8c839
commit e2c0d1de87
65 changed files with 2306 additions and 437 deletions

19
tools/README.md Normal file
View File

@@ -0,0 +1,19 @@
# Shell scripts
## Russian
Эти скрипты я писал в разное время для решения разных задач.
Чтобы они не растерялись по репозиториям и носителям, я решил собрать их здесь в одну кучу.
Я всегда использую Ubuntu в качестве своих настольных и серверных ОС, поэтому все эти скрипты писались и использовались в этих средах с версий 18.*.
Многие скрипты зависимы от [io.sh](/io.sh).
## English
These scripts were written at different times to solve different my own problems.
I decided to collect them here in a heap so that they are not lost in repositories and media.
I always use Ubuntu as my desktop and server OS, so all these scripts has been written and used in these environments since version 18.*.
Many scripts depending on [io.sh](/io.sh).

View File

@@ -0,0 +1,32 @@
#!/bin/bash
apt update && apt upgrade -y --autoremove
apt install -y \
apt-transport-https \
build-essential \
ca-certificates \
cmake \
curl \
dialog \
gettext \
gnupg \
htop \
libaio1 \
libcurl4-gnutls-dev \
libexpat1-dev \
libghc-zlib-dev \
libssl-dev \
make \
mc \
nano \
net-tools \
nmap \
p7zip-full \
software-properties-common \
unzip \
inotify-tools \
git \
mariadb-server \
mariadb-client \
nginx \
certbot

26
tools/dc Normal file
View File

@@ -0,0 +1,26 @@
#!/bin/bash
CONTAINER="my-container" # the name of the container in which to 'exec' something
CONFIG="$(dirname $([ -L $0 ] && readlink -f $0 || echo $0))/docker-compose.yml" # path to compose yml file
CMD="docker-compose -f $CONFIG" # docker-compose command
APP_URL='http://localhost:8000/'
open_browser() {
if which xdg-open > /dev/null; then
xdg-open "$1" </dev/null >/dev/null 2>&1 & disown
elif which gnome-open > /dev/null; then
gnome-open "$1" </dev/null >/dev/null 2>&1 & disown
fi
}
case "$1" in
'' | 'help' ) echo -e "Provide one of operations: \t start, stop, up, down, restart, rebuild, open";
echo "Otherwise all args will be passed to 'docker exec -ti $CONTAINER ...'" ;;
'open' ) open_browser $APP_URL ;;
'up' ) $CMD up -d --build ;; # build and start containers
'down' ) $CMD down --remove-orphans ;; # stop and remove containers
'start' ) $CMD start ;; # start containers
'stop' ) $CMD stop ;; # stop containers
'restart' ) $CMD stop && $CMD start ;; # restart containers
'rebuild' ) $CMD down --remove-orphans && $CMD up -d --build ;; # rebuild containers
* ) docker exec -ti $CONTAINER $@ # exec anything in container
esac

View File

@@ -1,54 +1,55 @@
#!/bin/bash
# https://gist.github.com/anthonyaxenov/c16e1181d4b8a8644c57ec8a1f6cf21c
#########################################################################
# #
# Set display resolution #
# Set output resolution #
# #
# Author: Anthony Axenov (Антон Аксенов) #
# Version: 1.0 #
# License: WTFPL #
# License: WTFPLv2 #
# #
#########################################################################
# #
# Using this script you can change your display resolution #
# Using this script you can change your output resolution #
# to any one you need. Just adjust some vars below and run script #
# (chmod +x needed). #
# #
#########################################################################
# https://gist.github.com/anthonyaxenov/c16e1181d4b8a8644c57ec8a1f6cf21c
# Set display name to work with. You can get it via 'xrandr --listactivemonitors'
display="HDMI-2"
# Set width of this display in px
width=1600
# Set height of this display in px
height=900
# Set output name to work with. You can get it via 'xrandr --listactivemonitors'
output="HDMI-3"
# Set width of this output in px
width=1920
# Set height of this output in px
height=1080
# Set refresh rate in Hz of this output in px
refresh=120
# Sometimes cvt and gtf generates different modelines.
# You can play around and look which of them gives best result:
modeline=$(cvt ${width} ${height} | grep "Modeline")
# modeline=$(gtf ${width} ${height} 60 | grep "Modeline")
modeline=$(cvt ${width} ${height} ${refresh} | grep "Modeline")
# modeline=$(gtf ${width} ${height} ${refresh} | grep "Modeline")
# Some important data needed to xrandr:
modename="${width}x${height}_my"
modename="${width}x${height}@${refresh}_my"
params=$(echo "$modeline" | sed "s|^\s*Modeline\s*\"[0-9x_.]*\"\s*||")
echo "Set resolution ${width}x${height} on display $display:"
echo "Set resolution ${width}x${height}@${refresh} on output $output:"
echo "$modename $params"
# Simple logic:
# 1. Switch display to safe mode which always exists (I believe) to avoid errors
xrandr --output $display --mode 640x480
# 2. If display aready have our mode -- we must delete it to avoid errors
# 1. Switch output to safe mode which always exists (I believe) to avoid errors
xrandr --output $output --mode 640x480 --verbose
# 2. If output aready have our mode -- we must delete it to avoid errors
if $(xrandr | grep -q "$modename"); then
# 2.1. Detach mode from display
xrandr --delmode $display $modename
# 2.1. Detach mode from output
xrandr --delmode $output $modename
# 2.2. Remove mode itself
xrandr --rmmode $modename
fi
# 3. Create new mode with freshly generated parameters
xrandr --newmode $modename $params
# 4. Attach mode to our display
xrandr --addmode $display $modename
# 5. Switch display to this mode immidiately
xrandr --output $display --mode $modename
xrandr --newmode $modename $params --verbose
# 4. Attach mode to our output
xrandr --addmode $output $modename --verbose
# 5. Switch output to this mode immidiately
xrandr --output $output --mode $modename --refresh $refresh --verbose

0
tools/free-space.sh Normal file → Executable file
View File

121
tools/init-home-mediasrv.sh Normal file
View File

@@ -0,0 +1,121 @@
#!/bin/bash
sudo apt update && sudo apt upgrade -y --autoremove
sudo apt install -y \
alien \
apt-transport-https \
build-essential \
ca-certificates \
cmake \
curl \
dconf-editor \
default-jdk \
dialog \
gettext \
gnupg \
gparted \
hardinfo \
htop \
libaio1 \
libcurl4-gnutls-dev \
libexpat1-dev \
libghc-zlib-dev \
libssl-dev \
lsb-release \
lsp-plugins \
make \
mc \
nano \
neofetch \
net-tools \
nmap \
p7zip-full \
easyeffects \
software-properties-common \
ubuntu-restricted-extras \
unzip \
vlc \
ffmpeg \
xclip \
inotify-tools \
notify-osd \
fonts-open-sans \
libnotify-bin \
gnome-software \
gnome-software-plugin-flatpak \
gnome-software-plugin-snap \
terminator \
geoclue-2.0 \
redshift \
redshift-gtk \
samba \
dkms
# https://selectel.ru/blog/tutorials/how-to-install-and-configure-samba-on-ubuntu-20-04/
# https://linuxconfig.org/how-to-configure-samba-server-share-on-ubuntu-22-04-jammy-jellyfish-linux
# https://phoenixnap.com/kb/ubuntu-samba
# https://computingforgeeks.com/install-and-configure-samba-server-share-on-ubuntu/
# https://linux.how2shout.com/how-to-install-samba-on-ubuntu-22-04-lts-jammy-linux/
sudo cp /etc/samba/smb.conf /etc/samba/smb.conf.bak
sudo bash -c 'grep -v -E "^#|^;" /etc/samba/smb.conf.bak | grep . > /etc/samba/smb.conf'
sudo systemctl enable --now smbd
sudo usermod -aG sambashare $USER
sudo smbpasswd -a $USER
sudo add-apt-repository -y ppa:agornostal/ulauncher && \
sudo apt install -y --autoremove ulauncher
curl -L https://yt-dl.org/downloads/latest/youtube-dl -o "${HOME}/.local/bin/youtube-dl" && \
sudo chmod +rx "${HOME}/.local/bin/youtube-dl"
wget "https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb" && \
sudo dpkg -i google-chrome-stable_current_amd64.deb
git clone https://github.com/aircrack-ng/rtl8812au.git && \
cd rtl8812au && \
sudo make dkms_install
sudo curl -s -o /usr/share/keyrings/syncthing-archive-keyring.gpg https://syncthing.net/release-key.gpg && \
echo "deb [signed-by=/usr/share/keyrings/syncthing-archive-keyring.gpg] https://apt.syncthing.net/ syncthing stable" | sudo tee /etc/apt/sources.list.d/syncthing.list && \
echo "deb [signed-by=/usr/share/keyrings/syncthing-archive-keyring.gpg] https://apt.syncthing.net/ syncthing candidate" | sudo tee /etc/apt/sources.list.d/syncthing.list && \
sudo apt update && sudo apt install -y --autoremove syncthing && \
wget "https://raw.githubusercontent.com/syncthing/syncthing/main/etc/linux-desktop/syncthing-start.desktop" -O $HOME/.local/share/applications/syncthing-start.desktop && \
wget "https://raw.githubusercontent.com/syncthing/syncthing/main/etc/linux-desktop/syncthing-ui.desktop" -O $HOME/.local/share/applications/syncthing-ui.desktop && \
ln -sf $HOME/.local/share/applications/syncthing-start.desktop $HOME/.config/autostart/syncthing-start.desktop
#####################################################################
sudo apt install -y kodi kodi-pvr-iptvsimple

View File

@@ -0,0 +1,5 @@
# Backing up photos from Syncthing
More info:
* 🇷🇺 [axenov.dev/резервное-копирование-фотографий-со](https://axenov.dev/резервное-копирование-фотографий-со/)
* 🇺🇸 (planned to translate)

View File

@@ -0,0 +1,19 @@
# Daemon file
# Place or symlink it to /etc/systemd/system/inotifywait-cp.service
# Enable and start: sudo systemctl enable --now inotifywait-cp
# Check it: sudo systemctl status inotifywait-cp
[Unit]
Description=Photosync from android
[Service]
Type=simple
Restart=always
# correct these parameters as needed:
User=user
WorkingDirectory=/home/user
ExecStart=bash /home/user/.local/bin/photosync-a53.sh
[Install]
WantedBy=network.target

View File

@@ -0,0 +1,59 @@
#!/bin/bash
# My use case:
# syncthing synchronizes ALL changes in DCIM directory on my android to PC.
# I wanted files to be copied somewhere else on my PC to stay forever, so I
# could sort them later and safely free some space on mobile without loss.
# Also I wish to have some stupid log with history of such events.
# inotify-tools package must be installed!
# CHANGE THIS PARAMETERS to ones you needed
dir_src="$HOME/Syncthing/Mobile/Camera"
dir_dest="$HOME/some/safe/place"
dir_logs="$HOME/inotifywait-cp-logs"
regexp="[0-9]{8}_[0-9]{6}.*\.(jpg|mp4|gif)"
print() {
echo -e "[`date '+%H:%M:%S'`] $*" \
| tee -a "$dir_logs/`date '+%Y%m%d'`.log"
}
copy () {
mkdir -p "$dir_src" "$dir_dest" "$dir_logs"
if [ -f "$dir_dest/$1" ]; then
print "SKIPPED:\t$dir_dest/$1"
else
cp "$dir_src/$1" "$dir_dest/$1"
print "COPIED:\t$dir_src/$1 => $dir_dest/$1"
fi
}
mkdir -p "$dir_src" "$dir_dest" "$dir_logs"
print "START\t========================="
# First, try to backup files synced since last exec of this script
ls -1 "$dir_src" \
| grep -E "^$regexp$" \
| while read filename; do copy "$filename"; done
# Next, run inotifywait against source directory with args:
# --quiet -- print less (only print events)
# --monitor -- don't stop after first event (like infinite loop)
# --event -- first syncthing creates hidden file to write data into
# then renames it according to source file name, so here
# we listen to MOVED_TO event to catch final filename
# --format %f -- print only filename
# --include -- filename regexp to catch event from, ensure your $regexp
# is correct or remove line 56 to catch synced ALL files
inotifywait \
--quiet \
--monitor \
--event moved_to \
--format %f \
--include "$regexp" \
"$dir_src" \
| while read filename; do copy "$filename"; done
print "FINISH\t========================="

View File

@@ -0,0 +1,157 @@
#!/bin/bash
# Welcome to amusement park!
[[ "$1" = '--help' ]] || [[ "$1" = '-h' ]] && cat <<EOF && exit
NetBeans docker wrapper for php
===============================
Anthony Axenov (c) 2023, The MIT License
https://axenov.dev
https://opensource.org/license/mit
Replacement host php interpreter with dockerized one to run & debug cli php scripts.
Usage:
./$(basename $0) --container=<NAME> [--map=<PATH1>:<PATH2>] [PHP_ARGS] <SCRIPT> [SCRIPT_ARGS]
Arguments:
--container : docker container where your SCRIPT is located. Required.
--map : sources path mapped from the host to container. Not required.
PATH1 is an absolute path to php sources directory on the host.
PATH2 is an absolute path of the same directory inside of container.
Delimiter ':' is required. If PATH1, PATH2 or delimiter is missed
or value is empty then error will be thrown.
PHP_ARGS : arguments you can pass to real php interpreter according to its --help.
Not required.
SCRIPT : a path to script file (.php) to be executed in container. Required.
Note that this file must exist inside or be available from that container.
SCRIPT_ARGS : arguments to call your script with. They will be passed to script as is.
Not required.
Read this article to know how to set this helper as interpreter for NetBeans:
ru: https://axenov.dev/netbeans-php-docker-xdebug-cli
en: https://axenov.dev/en/netbeans-php-docker-xdebug-cli-en
EOF
pwd=$(pwd) # current working directory
cmdline=($@) # copy currently called command line to array
collect_php_args=1 # should we collect php args or script ones?
quiet=0 # should we print some useful data before executing?
# find a path where this wrapper is located
wrapper_dir="$(dirname $0)"
# find a path where project is probably located
project_dir="$(dirname $wrapper_dir)"
# here we check if this wrapper is global or local
# but if it is set as global from nbproject dir of
# current project then it is not detected as global
# anyway behavior will be correct
nbproject="$(basename $wrapper_dir)"
[ "$nbproject" = 'nbproject' ] && is_global=0 || is_global=1
# prepare new array to collect php args
declare -a php_cmd=("docker" "exec")
# and another one for script args
declare -a script_args=()
# and one more for directory mapping
declare -a map_arr=()
# iterate over arguments we received from netbeans
for arg in "${cmdline[@]}"; do
# if this is a container name
if [ "${arg::11}" = '--container' ]; then
container="${arg:12}" # save it
php_cmd+=("$container" 'php') # add php itself
continue # jump to next iteration
fi
# if this is a path map
if [ "${arg::5}" = '--map' ]; then
map="${arg:6}" # save it
map_arr=(${map//:/ }) # split it and check if it is correct
if [ -z "${map_arr[0]}" ] || [ -z "${map_arr[1]}" ]; then
echo "ERROR: directory map is incorrect!"
echo "Use $0 --help to get info about how to use this wrapper."
echo "Exit code 3."
exit 3
fi
continue # jump to next iteration
fi
# if this is a container name
if [ "${arg::7}" = '--quiet' ]; then
quiet=1
continue # jump to next iteration
fi
# if this is an absolute path to a script file
if [ -f "$arg" ]; then
# make its path correct for container
if [ "$map" ]; then # when paths are mapped
# remove first part of map from an absolute filepath and append result to second map part
filepath="${map_arr[1]}${arg##${map_arr[0]}}"
else # when paths are NOT mapped
# remove project path from absolute filepath
filepath="${arg##$project_dir/}"
fi
php_cmd+=("$filepath") # append php args with filepath
collect_php_args=0 # now we need to collect script args
continue # jump to next iteration
fi
if [ "$collect_php_args" = 1 ]; then # if we collect php args
php_cmd+=("$arg") # add current arg to php args as is
continue # jump to next iteration
fi
script_args+=("$arg") # otherwise add current arg to script args as is
done
# docker container name is required so we must halt here if there is no one
if [ -z "$container" ]; then
echo "ERROR: no docker container is specified!" >&2
echo "Use $0 --help to get info about how to use this wrapper." >&2
echo "Exit code 1." >&2
exit 1
fi
# path to php script is also required so we must halt here too if there is no one
if [ -z "$filepath" ]; then
echo "ERROR: no script filepath is specified!" >&2
echo "Use $0 --help to get info about how to use this wrapper." >&2
echo "Exit code 2." >&2
exit 2
fi
cmdline="${php_cmd[*]} ${script_args[*]}" # make a command to execute
# print some important data collected above
if [ "$quiet" = 0 ]; then
echo "NetBeans docker wrapper for php"
echo "==============================="
echo -e "Container name: $container"
echo -e "Script path: $filepath"
echo -e "Directory mapping: ${map:-(none)}"
echo -e "Command line:\n$cmdline\n"
fi
# some debug output
# echo "=== some debug output ========="
# cat <<EOF | column -t
# is_global $is_global
# container $container
# pwd $pwd
# wrapper_dir $wrapper_dir
# nbproject $nbproject
# project_dir $project_dir
# map $map
# map_arr[0] ${map_arr[0]}
# map_arr[1] ${map_arr[1]}
# filepath $filepath
# EOF
# echo "==============================="
$cmdline # execute
# that's folks!

View File

@@ -1,16 +1,15 @@
#!/bin/bash
# https://gist.github.com/anthonyaxenov/b8336a2bc9e6a742b5a050fa2588d71e
#####################################################################
# #
# Stupidly simple backup script for own projects #
# #
# Author: Anthony Axenov (Антон Аксенов) #
# Version: 1.0 #
# License: WTFPLv2 More info (RU): https://axenov.dev/?p=1234 #
# License: WTFPLv2 More info: https://axenov.dev/?p=1423 #
# #
#####################################################################
# https://gist.github.com/anthonyaxenov/b8336a2bc9e6a742b5a050fa2588d71e
# database credentials ==============================================
DBUSER=

72
tools/rsync-backup.sh Executable file
View File

@@ -0,0 +1,72 @@
#!/bin/bash
RS_SRC_DEV=/dev/sdb1
RS_DST_DEV=/dev/sdc1
LOG_DIR="/home/$USER/rsync-logs"
USE_NTFY=0
NTFY_TITLE="Backup: $RS_SRC_DEV => $RS_DST_DEV"
NTFY_CHANNEL=""
log() {
[ ! -d "$LOG_DIR" ] && mkdir -p "$LOG_DIR"
echo -e "[`date '+%H:%M:%S'`] $*" | tee -a "$LOG_DIR/`date '+%Y%m%d'`.log"
}
# отправляет простую нотификацию
ntfy_info() {
[ $USE_NTFY == 1 ] && ntfy send \
--title "$NTFY_TITLE" \
--message "$1" \
--priority 1 \
"$NTFY_CHANNEL"
}
# отправляет нотификацию с предупреждением
ntfy_warn() {
[ $USE_NTFY == 1 ] && ntfy send \
--title "$NTFY_TITLE" \
--tags "warning" \
--message "$1" \
--priority 5 \
"$NTFY_CHANNEL"
}
log "START\t========================="
mnt_check=$(findmnt -nf "$RS_SRC_DEV")
if [ $? -gt 0 ]; then
log "Source partition '$RS_SRC_DEV' is not mounted. Exit 1."
exit 1
fi
RS_SRC_PATH=$(echo $mnt_check | awk '{ print $1 }')
log "Source partition '$RS_SRC_DEV' is mounted at '$RS_SRC_PATH'"
mnt_check=$(findmnt -nf "$RS_DST_DEV")
if [ $? -gt 0 ]; then
log "Destination partition '$RS_DST_DEV' is not mounted. Exit 1."
exit 1
fi
RS_DST_PATH=$(echo $mnt_check | awk '{ print $1 }')
log "Destination partition '$RS_DST_DEV' is mounted at '$RS_DST_PATH'"
log "Executing rsync:"
rsync -huva \
--progress \
--delete \
--exclude='lost+found' \
--exclude='.Trash' \
"$RS_SRC_PATH/" \
"$RS_DST_PATH/" \
| while read line; do log "$line"; done
if [ $? -gt 0 ]; then
log "Something went wrong. Exit 3."
ntfy_warn "Something went wrong, check log"
exit 3
fi
ntfy_info "Success!"
log "FINISH\t========================="

18
tools/s3-backup-old.sh Executable file
View File

@@ -0,0 +1,18 @@
#!/bin/bash
TTL_DAYS=1
S3="s3://......"
OLDER_THAN=$(date -d "$TTL_DAYS days ago" "+%s")
echo $OLDER_THAN
s3cmd ls -r $S3 | while read -r line; do
FILETIME=$(echo "$line" | awk {'print $1" "$2'})
FILETIME=$(date -d "$FILETIME" "+%s")
echo $FILETIME - $OLDER_THAN
if [[ $FILETIME -le $OLDER_THAN ]]; then
FILEPATH=$(echo "$line" | awk {'print $4'})
if [ $FILEPATH != "" ]; then
printf 'Must delete: %s\n' $FILEPATH
echo "s3cmd del $FILEPATH"
fi
fi
done

342
tools/s3-backup.sh Normal file
View File

@@ -0,0 +1,342 @@
#!/bin/bash
#####################################################################
# #
# Stupidly simple backup script for own projects #
# #
# Author: Anthony Axenov (Антон Аксенов) #
# Version: 1.2 #
# License: WTFPLv2 #
# More info (RU): https://axenov.dev/?p=1272 #
# #
#####################################################################
# use remote storages ===============================================
USE_SSH=1
USE_S3=1
# database credentials ==============================================
DBUSER=
DBPASS=
DBNAME=
DBCHARSET="utf8"
# dates for file structure ==========================================
TODAY_DIR="$(date +%Y.%m.%d)"
TODAY_FILE="$(date +%H.%M)"
# local storage =====================================================
LOCAL_BAK_DIR="/backup"
LOCAL_BAK_PATH="$LOCAL_BAK_DIR/$TODAY_DIR"
# database backup file
LOCAL_SQL_FILE="$TODAY_FILE-db.sql.gz"
LOCAL_SQL_PATH="$LOCAL_BAK_PATH/$LOCAL_SQL_FILE"
# project path and backup file
LOCAL_SRC_DIR="/var/www/html"
LOCAL_SRC_FILE="$TODAY_FILE-src.tar.gz"
LOCAL_SRC_PATH="$LOCAL_BAK_PATH/$LOCAL_SRC_FILE"
# log file
LOG_FILE="$TODAY_FILE.log"
LOG_PATH="$LOCAL_BAK_PATH/$LOG_FILE"
# remote storages ===================================================
SSH_HOST="user@example.com"
SSH_BAK_DIR="/backup"
SSH_BAK_PATH="$SSH_BAK_DIR/$TODAY_DIR"
SSH_SQL_FILE="$SSH_BAK_PATH/$LOCAL_SQL_FILE"
SSH_SRC_FILE="$SSH_BAK_PATH/$LOCAL_SRC_FILE"
SSH_LOG_FILE="$SSH_BAK_PATH/$LOG_FILE"
S3_BUCKET="s3://my.bucket"
S3_DIR="$S3_BUCKET/$TODAY_DIR"
S3_SQL_FILE="$S3_DIR/$LOCAL_SQL_FILE"
S3_SRC_FILE="$S3_DIR/$LOCAL_SRC_FILE"
S3_LOG_FILE="$S3_DIR/$LOG_FILE"
# autoremove ========================================================
# time to live on different storages
TTL_LOCAL=3
TTL_SSH=7
TTL_S3=60
# autoremove flags
CLEAR_SSH=1
CLEAR_S3=1
# notifications =====================================================
USE_NTFY=1
NTFY_TITLE="Backup script"
NTFY_CHANNEL=
#====================================================================
#
# Functions used for the whole backup flow
#
#====================================================================
# prints arguments to stdout and into log file
log() {
echo -e "[$(date +%H:%M:%S)] $*" | tee -a "$LOG_PATH"
}
# sends notification with information
ntfy_info() {
[ $USE_NTFY == 1 ] && ntfy send \
--title "$NTFY_TITLE" \
--message "$1" \
--priority 1 \
"$NTFY_CHANNEL"
}
# sends notification with warning
ntfy_warn() {
[ $USE_NTFY == 1 ] && ntfy send \
--title "$NTFY_TITLE" \
--tags "warning" \
--message "$1" \
--priority 5 \
"$NTFY_CHANNEL"
}
# prints initialized parameters
show_params() {
log "Initialized parameters:"
log "├ [ Remotes ]"
log "│\t├ USE_SSH = $USE_SSH"
[ $USE_SSH == 1 ] && log "│\t├ SSH_HOST = $SSH_HOST"
log "│\t├ USE_S3 = $USE_S3"
[ $USE_S3 == 1 ] && log "│\t├ S3_BUCKET = $S3_BUCKET"
log "├ [ Database ]"
log "│\t├ DBUSER = $DBUSER"
log "│\t├ DBNAME = $DBNAME"
log "│\t├ DBCHARSET = $DBCHARSET"
log "│\t├ LOCAL_SQL_PATH = $LOCAL_SQL_PATH"
[ $USE_SSH == 1 ] && log "│\t├ SSH_SQL_FILE = $SSH_SQL_FILE"
[ $USE_S3 == 1 ] && log "│\t├ S3_SQL_FILE = $S3_SQL_FILE"
log "├ [ Sources ]"
log "│\t├ LOCAL_SRC_DIR = $LOCAL_SRC_DIR"
log "│\t├ LOCAL_SRC_PATH = $LOCAL_SRC_PATH"
[ $USE_SSH == 1 ] && log "│\t├ SSH_SRC_FILE = $SSH_SRC_FILE"
[ $USE_S3 == 1 ] && log "│\t├ S3_SRC_FILE = $S3_SRC_FILE"
log "├ [ Log ]"
log "│\t├ LOG_PATH = $LOG_PATH"
[ $USE_SSH == 1 ] && log "│\t├ SSH_LOG_FILE = $SSH_LOG_FILE"
[ $USE_S3 == 1 ] && log "│\t├ S3_LOG_FILE = $S3_LOG_FILE"
log "├ [ Autoclear ]"
log "│\t├ TTL_LOCAL = $TTL_LOCAL"
[ $USE_SSH == 1 ] && {
log "│\t├ CLEAR_SSH = $CLEAR_SSH"
log "│\t├ TTL_SSH = $TTL_SSH"
}
[ $USE_S3 == 1 ] && {
log "│\t├ CLEAR_S3 = $CLEAR_S3"
log "│\t├ TTL_S3 = $TTL_S3"
}
log "└ [ ntfy ]"
log "\t├ USE_NTFY = $USE_NTFY"
[ $USE_NTFY == 1 ] && log "\t├ NTFY_TITLE = $NTFY_TITLE"
[ $USE_NTFY == 1 ] && log "\t└ NTFY_CHANNEL = $NTFY_CHANNEL"
}
# initializes directories for backup
init_dirs() {
if [ ! -d "$LOCAL_BAK_PATH" ]; then
mkdir -p $LOCAL_BAK_PATH
fi
[ $USE_SSH == 1 ] && ssh $SSH_HOST "mkdir -p $SSH_BAK_PATH"
}
# clears old local backups
clear_local_backups() {
log "\tLocal:"
log $(find "$LOCAL_BAK_DIR" -type d -mtime +"$TTL_LOCAL" | sort)
find "$LOCAL_BAK_DIR" -type d -mtime +"$TTL_LOCAL" | xargs rm -rf
}
# clears old backups on remote ssh storage
clear_ssh_backups() {
if [ $USE_SSH == 1 ] && [ $CLEAR_SSH == 1 ]; then
log "\tSSH:"
log $(ssh "$SSH_HOST" "find $SSH_BAK_DIR -type d -mtime +$TTL_SSH" | sort)
ssh "$SSH_HOST" "find $SSH_BAK_DIR -type d -mtime +$TTL_SSH | xargs rm -rf"
else
log "\tSSH: disabled (\$USE_SSH, \$CLEAR_SSH)"
fi
}
# clears backups on remote s3 storage
clear_s3_backups() {
# https://gist.github.com/JProffitt71/9044744?permalink_comment_id=3539681#gistcomment-3539681
if [ $USE_S3 == 1 ] && [ $CLEAR_S3 == 1 ]; then
log "\tS3:"
OLDER_THAN=$(date -d "$TTL_S3 days ago" "+%s")
s3cmd ls -r $S3_DIR | while read -r line; do
FILETIME=$(echo "$line" | awk {'print $1" "$2'})
FILETIME=$(date -d "$FILETIME" "+%s")
if [[ $FILETIME -le $OLDER_THAN ]]; then
FILEPATH=$(echo "$line" | awk {'print $4'})
if [ $FILEPATH != "" ]; then
log "$line"
s3cmd del $FILEPATH
fi
fi
done
else
log "\tS3: disabled (\$USE_S3 + \$CLEAR_S3)"
fi
}
# clears old backups
clear_backups() {
echo
log "1/7 Removing old backups..."
clear_local_backups
clear_ssh_backups
clear_s3_backups
}
# makes archive with database dump
backup_db() {
echo
log "2/7 Dumping DB: $DBNAME..."
mysqldump \
--user=$DBUSER \
--password=$DBPASS \
--opt \
--default-character-set=$DBCHARSET \
--quick \
$DBNAME | gzip > $LOCAL_SQL_PATH
if [ $? == 0 ]; then
log "\t- OK"
send_db_ssh
send_db_s3
else
log "\t- ERROR: failed to create dump. Exit-code: $?"
ntfy_warn "ERROR: failed to create dump"
log "3/7 Sending database backup to $SSH_HOST... skipped"
log "4/7 Sending database backup to $S3_DIR... skipped"
fi
}
# sends database archive into ssh remote storage
send_db_ssh() {
echo
log "3/7 Sending database backup to $SSH_HOST..."
if [ $USE_SSH == 1 ]; then
rsync --progress "$LOCAL_SQL_PATH" "$SSH_HOST:$SSH_SQL_FILE"
if [ $? == 0 ]; then
log "\t- OK"
else
log "\t- ERROR: failed to send DB backup to $SSH_HOST. Exit-code: $?"
ntfy_warn "ERROR: failed to send DB backup to $SSH_HOST"
fi
else
log "\t- disabled (\$USE_SSH)"
fi
}
# sends database archive into s3 remote storage
send_db_s3() {
echo
log "4/7 Sending database backup to $S3_DIR..."
if [ $USE_S3 == 1 ]; then
s3cmd put "$LOCAL_SQL_PATH" "$S3_SQL_FILE"
if [ $? == 0 ]; then
log "\t- OK"
else
log "\t- ERROR: failed to send DB backup to $S3_DIR. Exit-code: $?"
ntfy_warn "ERROR: failed to send DB backup to $S3_DIR"
fi
else
log "\t- disabled (\$USE_SSH)"
fi
}
# makes archive with project sources
backup_src() {
echo
log "5/7 Compressing project dir: $LOCAL_SRC_DIR..."
tar -zcf "$LOCAL_SRC_PATH" "$LOCAL_SRC_DIR"
if [ $? == 0 ]; then
log "\t- OK"
send_src_ssh
send_src_s3
else
log "\t- ERROR: failed to compress project. Exit-code: $?"
ntfy_warn "ERROR: failed to compress project"
log "6/7 Sending project backup to $SSH_HOST... skipped"
log "7/7 Sending project backup to $S3_DIR... skipped"
fi
}
# sends sources archive into ssh remote storage
send_src_ssh() {
echo
log "6/7 Sending project backup to $SSH_HOST..."
if [ $USE_SSH == 1 ]; then
rsync --progress "$LOCAL_SRC_PATH" "$SSH_HOST:$SSH_SRC_FILE"
if [ $? == 0 ]; then
log "\t- OK"
else
log "\t- ERROR: failed to send project backup to $SSH_HOST. Exit-code: $?"
ntfy_warn "ERROR: failed to send project backup to $SSH_HOST"
fi
else
log "\t- disabled"
fi
}
# sends sources archive into s3 remote storage
send_src_s3() {
echo
log "7/7 Sending project backup to $S3_DIR..."
s3cmd put "$LOCAL_SRC_PATH" "$S3_SRC_FILE"
if [ $? == 0 ]; then
log "\t- OK"
else
log "\t- ERROR: failed to send database backup to $S3_DIR. Exit-code: $?"
ntfy_warn "ERROR: failed to send project backup to $S3_DIR"
fi
}
# prints used/free space on local storage
show_finish() {
echo
log "Finish!"
log "Used space: $(du -h "$LOCAL_BAK_PATH" | tail -n1)" # вывод размера папки с бэкапами за текущий день
log "Free space: $(df -h "$LOCAL_BAK_PATH" | tail -n1 | awk '{print $4}')" # вывод свободного места на локальном диске
echo
}
# sends log file into both remote storage
send_log() {
[ $USE_SSH == 1 ] && rsync --progress "$LOG_PATH" "$SSH_HOST:$SSH_LOG_FILE"
[ $USE_S3 == 1 ] && s3cmd put "$LOG_PATH" "$S3_LOG_FILE"
}
# main flow =========================================================
log "Start ----------------------------------------------------------"
show_params
init_dirs
clear_backups
backup_db
backup_src
show_finish
send_log
ntfy_info "Finish!"

40
tools/setup-wakeonlan.sh Executable file
View File

@@ -0,0 +1,40 @@
#!/bin/bash
print() {
echo -e "$*"
}
state() {
sudo ethtool "$iface" | grep -E '^\s+Wake-on:\s\w+' | awk '{print $2}'
}
[ "$1" ] && iface="$1" || iface=enp3s0
[ -f "/sys/class/net/$iface/address" ] && mac=$(cat "/sys/class/net/$iface/address") || mac=''
[ -z "$mac" ] && {
print "Wrong interface! $iface" >&2
exit 1
}
state=$(state)
print "Interface\t: $iface"
print "MAC-address\t: $mac"
print "WoL state\t: $state"
if [ $state == 'd' ]; then
sudo ethtool -s "$iface" wol gu || true
sudo mkdir -p /etc/networkd-dispatcher/configuring.d
sudo tee /etc/networkd-dispatcher/configuring.d/wol <<EOF >/dev/null
#!/usr/bin/env bash
ethtool -s $iface wol gu || true
EOF
sudo chmod 755 /etc/networkd-dispatcher/configuring.d/wol
print "* New WOL state\t: $(state)"
fi
print "\nTo wake up this device run this command from another one:\n"
print "\twakeonlan -p 8 $mac\n"
print "\twol $mac\n"

49
tools/upgrade-ubuntu.sh Executable file
View File

@@ -0,0 +1,49 @@
#!/bin/bash
# https://dev.to/chefgs/upgrading-an-end-of-life-eol-ubuntu-os-to-lts-version-3a36
# https://changelogs.ubuntu.com/meta-release
installed() {
command -v "$1" >/dev/null 2>&1
}
# sudo software-properties-qt (переключиться с LTS на нормальные релизы)
# sudo aptitude install update-manager-core update-manager
# sudo apt upgrade --autoremove -y
# installed pkcon && sudo pkcon update --autoremove -y
# sudo apt dist-upgrade
# sudo apt install update-manager-core
# sudo do-release-upgrade -p
source /etc/os-release
echo "Loading..."
IFS=$'\n' codenames=($(curl -s https://changelogs.ubuntu.com/meta-release | grep -xP "^Dist:\s[\w]+$" | sed "s/Dist: //" ))
thisCodename="$VERSION_CODENAME"
for idx in "${!codenames[@]}"; do
if [ "${codenames[idx]}" = "$thisCodename" ]; then
nextCodename=${codenames[((idx+1))]}
fi
done
targetDownloadPath="`pwd`/upgrade-$nextCodename"
targetToolPath="$targetDownloadPath/unpacked"
targetToolFile="$targetDownloadPath/$nextCodename.tar.gz"
echo "Current dist: $thisCodename"
echo "Next dist: $nextCodename"
echo "Target path: $targetToolFile"
rm -rf "$targetToolPath"
mkdir -p "$targetToolPath"
echo "Downloading..."
cd "$targetDownloadPath"
wget "http://archive.ubuntu.com/ubuntu/dists/${nextCodename}-updates/main/dist-upgrader-all/current/${nextCodename}.tar.gz"
echo "Unpacking..."
tar -xaf "$targetToolFile" -C "$targetToolPath"
echo "Starting..."
cd unpacked
sudo ./$nextCodename

82
tools/vscode-ext.sh Normal file
View File

@@ -0,0 +1,82 @@
#!/bin/bash
exts=(
'af4jm.vscode-m3u'
'ahmadalli.vscode-nginx-conf'
'akamud.vscode-theme-onedark'
'anweber.statusbar-commands'
'baincd.mini-command-palettes'
'bmewburn.vscode-intelephense-client'
'codezombiech.gitignore'
'cweijan.vscode-redis-client'
'darkriszty.markdown-table-prettify'
'davidmarek.jsonpath-extract'
'deitry.apt-source-list-syntax'
'devsense.composer-php-vscode'
'devsense.intelli-php-vscode'
'devsense.phptools-vscode'
'devsense.profiler-php-vscode'
'dotjoshjohnson.xml'
'dunstontc.vscode-go-syntax'
'dustypomerleau.rust-syntax'
'eamodio.gitlens'
'editorconfig.editorconfig'
'esbenp.prettier-vscode'
'furkanozalp.go-syntax'
'gigacode.gigacode-vscode'
'golang.go'
'grapecity.gc-excelviewer'
'humao.rest-client'
'irongeek.vscode-env'
'jebbs.plantuml'
'jeff-hykin.better-go-syntax'
'jeppeandersen.vscode-kafka'
'jflbr.jwt-decoder'
'jinsihou.diff-tool'
'jtr.vscode-position'
'kenhowardpdx.vscode-gist'
'leavesster.jsonpath'
'mads-hartmann.bash-ide-vscode'
'mamoru.vscode-fish-text'
'mechatroner.rainbow-csv'
'mehedidracula.php-namespace-resolver'
'mhutchie.git-graph'
'mrmlnc.vscode-apache'
'ms-azuretools.vscode-docker'
'ms-ceintl.vscode-language-pack-ru'
'ms-vscode.hexeditor'
'ms-vscode.makefile-tools'
'neilbrayfield.php-docblocker'
'neonxp.gotools'
'nickdemayo.vscode-json-editor'
'nico-castell.linux-desktop-file'
'open-rpc.open-rpc'
'pejmannikram.vscode-auto-scroll'
'pkief.material-icon-theme'
'qcz.text-power-tools'
'rogalmic.bash-debug'
'rust-lang.rust-analyzer'
'ryu1kn.partial-diff'
'srmeyers.git-prefix'
'sumneko.lua'
'syler.ignore'
'takumii.markdowntable'
'tamasfe.even-better-toml'
'tyriar.lorem-ipsum'
'vitorsalgado.vscode-redis'
'waderyan.gitblame'
'wayou.vscode-todo-highlight'
'weijunyu.vscode-json-path'
'xdebug.php-debug'
'yinfei.luahelper'
'yog.yog-plantuml-highlight'
'yves.schema-tree'
'yzane.markdown-pdf'
'yzhang.markdown-all-in-one'
'zgm.cuesheet'
'zh9528.file-size'
'zobo.php-intellisense'
)
for ext in "$exts[@]"; do
code --install-extension $ext
done

0
tools/ytdlcue.sh Executable file → Normal file
View File