init
This commit is contained in:
commit
bb07073c6a
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
untracked/
|
25
README
Normal file
25
README
Normal file
@ -0,0 +1,25 @@
|
||||
A lot of Shell scripts.
|
||||
|
||||
Scripts
|
||||
-------
|
||||
|
||||
appimage AppImages manager.
|
||||
btw Track battery and send notify if low battery.
|
||||
codes Print ANSI sequences (16, 256 colors and formatting).
|
||||
currency Get currencies from Russian Central Bank and calculate.
|
||||
dots Dotfiles manager. Save and push selected files to git repo.
|
||||
github-starred-repos Get list of user's starred repos from GitHub.
|
||||
git-mass-clone Mass clone or pull repos from file.
|
||||
http Python 3 http.server runner.
|
||||
log Logs viewing tool (nginx and exim4). Prints logs to STDOUT.
|
||||
md2 Convert Markdown to HTML, ROFF and PDF. Pandoc wrapper.
|
||||
mega MEGAcmd wrapper.
|
||||
parts Store and view code snippets.
|
||||
rand Print random array item.
|
||||
safeeject Safely remove an external drive. Useful for USB-devices.
|
||||
unflac Convert FLAC to MP3.
|
||||
upload Upload files to remote server via server alias.
|
||||
view Print highlighted text to STDOUT. highlight wrapper.
|
||||
yad Download file from Yandex.Disk storage.
|
||||
|
||||
Most scripts have an builtin help text. Try `%scriptname% --help`.
|
24
UNLICENSE
Normal file
24
UNLICENSE
Normal file
@ -0,0 +1,24 @@
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
245
src/appimage
Executable file
245
src/appimage
Executable file
@ -0,0 +1,245 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# * appimage - Manage AppImages on system.
|
||||
#
|
||||
# This is free and unencumbered software released into the public domain.
|
||||
#
|
||||
# Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
# distribute this software, either in source code form or as a compiled
|
||||
# binary, for any purpose, commercial or non-commercial, and by any
|
||||
# means.
|
||||
#
|
||||
# In jurisdictions that recognize copyright laws, the author or authors
|
||||
# of this software dedicate any and all copyright interest in the
|
||||
# software to the public domain. We make this dedication for the benefit
|
||||
# of the public at large and to the detriment of our heirs and
|
||||
# successors. We intend this dedication to be an overt act of
|
||||
# relinquishment in perpetuity of all present and future rights to this
|
||||
# software under copyright law.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
# OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# For more information, please refer to <http://unlicense.org/>
|
||||
|
||||
set -o errexit
|
||||
cache_dir="$HOME/.cache/appimage"
|
||||
appimages_info="$HOME/.config/appimages.info"
|
||||
PREFIX="${PREFIX:-$HOME/.local}"
|
||||
ASSUME_YES="${ASSUME_YES:-}"
|
||||
|
||||
print_help() {
|
||||
cat <<- EOF
|
||||
Manage AppImages.
|
||||
|
||||
Usage: $0 [options] [<arguments>]
|
||||
|
||||
Options:
|
||||
-i, --install install AppImage from URL or from FILE.
|
||||
-d, --no-desktop don't create a desktop file. See https://www.freedesktop.org/wiki/Specifications/desktop-entry-spec/
|
||||
-p, --prefix installation prefix [default: $PREFIX]
|
||||
-r, --remove remove AppImage.
|
||||
-l, --list list installed AppImages.
|
||||
-s, --show show AppImage related info.
|
||||
-y, --yes automatic yes to prompts.
|
||||
-h, --help print this help message and exit.
|
||||
-v, --version print version and exit.
|
||||
|
||||
Environment:
|
||||
PREFIX default installation prefix.
|
||||
ASSUME_YES automatic yes to prompts.
|
||||
EOF
|
||||
}
|
||||
|
||||
yesno() {
|
||||
# Yes/No interactive dialog.
|
||||
#
|
||||
# Usage: if yesno 'Question'; then ...
|
||||
local answer=
|
||||
[ "$ASSUME_YES" ] && return 0
|
||||
|
||||
while [ ! "$answer" ]; do
|
||||
echo -en "$* (y/n) "
|
||||
read -r reply
|
||||
case "${reply,,}" in
|
||||
y|yes) answer=0;;
|
||||
n|no) answer=1;;
|
||||
*) echo "Please, answer y or n";;
|
||||
esac
|
||||
done
|
||||
return "$answer"
|
||||
}
|
||||
|
||||
# https://stackoverflow.com/a/49197786
|
||||
extract() {
|
||||
tar -xOvaf "$1" 2>/dev/null > "$2" && return 0
|
||||
case $(file "$1") in
|
||||
*bzip2*) bzip2 -dkc "$1" > "$2" ;;
|
||||
*gzip*) gunzip -c "$1" > "$2" ;;
|
||||
*'7-zip'*) 7z e -so "$1" > "$2" ;;
|
||||
*zip*) ;&
|
||||
*Zip*) unzip -p "$1" > "$2" ;;
|
||||
*xz*) ;&
|
||||
*XZ*) unxz -c "$1" > "$2" ;;
|
||||
*) return 1;;
|
||||
esac
|
||||
}
|
||||
|
||||
install_appimage() {
|
||||
local image desktop_file name file version description desktop
|
||||
|
||||
if [ -f "$1" ]; then
|
||||
image="$1"
|
||||
elif [[ "$1" =~ https?://.+ ]]; then
|
||||
echo -e "\e[1m==> Download AppImage ...\e[0m"
|
||||
mkdir -p "$cache_dir"
|
||||
image="$cache_dir/temporary.AppImage"
|
||||
wget -c "$1" -O "$image"
|
||||
else
|
||||
echo No such file: "$1" >&2; exit 1
|
||||
fi
|
||||
|
||||
local uncompressed_image="$cache_dir/temporary.AppImage.uncompressed"
|
||||
if extract "$image" "$uncompressed_image"; then
|
||||
image="$uncompressed_image"
|
||||
fi
|
||||
|
||||
# Check file type
|
||||
if [[ ! "$(file "$image")" =~ .*ELF.* ]]; then
|
||||
echo File is not correct Linux binary. >&2; exit 1
|
||||
fi
|
||||
|
||||
chmod +x "$image"
|
||||
|
||||
echo -e "\e[1m==> Extracting data ...\e[0m"
|
||||
|
||||
desktop_file="$("$image" --appimage-extract '*.desktop')"
|
||||
name="$(grep -Po '(?<=Name=)(.*)' "$desktop_file")"
|
||||
version="$(grep -Po '(?<=X-AppImage-Version=)(.*)' "$desktop_file")"
|
||||
description="$(grep -Po '(?<=Comment=)(.*)' "$desktop_file")"
|
||||
file="$PREFIX/bin/${name}-${version}.AppImage"
|
||||
|
||||
echo -e "\e[1m==> Install ...\e[0m"
|
||||
|
||||
# Install files
|
||||
install -Dm755 -D "$image" "$file"
|
||||
if [ -n "$no_desktop" ]; then
|
||||
desktop=None
|
||||
else
|
||||
desktop="$PREFIX/share/applications/${name}-${version}.desktop"
|
||||
install -Dm644 -D "$desktop_file" "$desktop"
|
||||
sed '/Exec=/d' -i "$desktop"; echo "Exec=$file" >> "$desktop"
|
||||
rm "${desktop_file:-/nonexistent}"
|
||||
rmdir "$PWD/squashfs-root"
|
||||
fi
|
||||
|
||||
# Clean cache
|
||||
[ -f "$cache_dir/temporary.AppImage" ] && rm "$cache_dir/temporary.AppImage"
|
||||
[ -f "$cache_dir/temporary.AppImage.uncompressed" ] && rm "$cache_dir/temporary.AppImage.uncompressed"
|
||||
|
||||
# Save App data
|
||||
printf "%s:%s:%s:%s:%s\n" "$name" "$version" "$description" "$file" "$desktop" >> "$appimages_info"
|
||||
echo Done.
|
||||
|
||||
echo -e "\e[1mRecap:\e[0m"
|
||||
echo APPIMAGE: "$name"
|
||||
echo VERSION: "$version"
|
||||
echo EXECUTABLE: "$file"
|
||||
echo DESKTOP FILE: "$desktop"
|
||||
|
||||
if [[ ! "$PATH" =~ "$PREFIX" ]]; then
|
||||
echo
|
||||
echo PREFIX is not in PATH!
|
||||
echo Add this line to your \~/.bashrc file:
|
||||
echo
|
||||
echo export PATH="$PREFIX:$PATH"
|
||||
echo
|
||||
echo and restart your Shell session.
|
||||
fi
|
||||
}
|
||||
|
||||
remove_appimage() {
|
||||
local appimage _appimage name version file desktop
|
||||
appimage="$1"
|
||||
|
||||
if [ -f "$appimages_info" ]; then
|
||||
if awk -F: '{print $1 ":" $2}' "$appimages_info" | grep -i "^${appimage}\$" >/dev/null; then
|
||||
_appimage="$(grep -i "$appimage" "$appimages_info")"
|
||||
name="$(awk -F: '{print $1}' <<< "$_appimage")"
|
||||
version="$(awk -F: '{print $2}' <<< "$_appimage")"
|
||||
file="$(awk -F: '{print $4}' <<< "$_appimage")"
|
||||
desktop="$(awk -F: '{print $5}' <<< "$_appimage")"
|
||||
|
||||
echo AppImage: "$name"
|
||||
echo Version: "$version"
|
||||
echo Remove:
|
||||
echo "$file"
|
||||
echo "$desktop"
|
||||
if yesno 'Are you sure?'; then
|
||||
[ -f "$file" ] && rm "$file"
|
||||
[ -f "$desktop" ] && rm "$desktop"
|
||||
sed -e "/$appimage/Id" -i "$appimages_info" # Remove App data
|
||||
echo "$appimage" removed.
|
||||
else
|
||||
echo Abort
|
||||
fi
|
||||
else
|
||||
echo AppImage not found: "$appimage"
|
||||
echo Note: Specify AppImage name and version separated by a colon e.g. SomeApp:1.8.2, case insensitive.
|
||||
fi
|
||||
else
|
||||
echo No AppImages installed. >&2; exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
list_appimages() {
|
||||
# shellcheck disable=SC2002
|
||||
cat "$appimages_info" 2>/dev/null | awk -F: \
|
||||
'BEGIN {print "NAME:VERSION:DESCRIPTION"} {print $1 ":" $2 ":" $3}' | column -t -s :
|
||||
}
|
||||
|
||||
show_appimage() {
|
||||
cat "$appimages_info" 2>/dev/null | grep -i -m 1 "$1" |
|
||||
awk -F: '{print "APPIMAGE: " $1 "\nVERSION: " $2 "\nDESCRIPTION: " $3 "\nEXECUTABLE: " $4 "\nDESKTOP FILE: " $5}'
|
||||
}
|
||||
|
||||
# Print help if no arguments passed
|
||||
[[ "$#" == 0 ]] && { print_help; exit 1; }
|
||||
|
||||
# Transform long options to short ones
|
||||
for arg in "$@"; do
|
||||
shift
|
||||
case "$arg" in
|
||||
--install) set -- "$@" "-i";;
|
||||
--no-desktop) set -- "$@" "-d";;
|
||||
--prefix) set -- "$@" "-p";;
|
||||
--remove) set -- "$@" "-r";;
|
||||
--list) set -- "$@" "-l";;
|
||||
--show) set -- "$@" "-s";;
|
||||
--yes) set -- "$@" "-y";;
|
||||
--help) set -- "$@" "-h";;
|
||||
--version) set -- "$@" "-v";;
|
||||
*) set -- "$@" "$arg";;
|
||||
esac
|
||||
done
|
||||
|
||||
# Parse short options
|
||||
while getopts ":i:dp:r:ls:yhv" opt; do
|
||||
case "$opt" in
|
||||
i) install_appimage "$OPTARG"; exit "$?";;
|
||||
d) no_desktop='yes';;
|
||||
p) PREFIX="$OPTARG"; ;;
|
||||
r) remove_appimage "$OPTARG"; exit "$?";;
|
||||
l) list_appimages; exit $?;;
|
||||
s) show_appimage "$OPTARG"; exit "$?";;
|
||||
y) ASSUME_YES=1;;
|
||||
h) print_help; exit 0;;
|
||||
v) echo 0.2.0; exit 0;;
|
||||
*) echo "Unknown option $opt" >&2; exit 1;;
|
||||
esac
|
||||
done
|
187
src/btw
Executable file
187
src/btw
Executable file
@ -0,0 +1,187 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# * Battery Watchdog (see help text below).
|
||||
#
|
||||
# This is free and unencumbered software released into the public domain.
|
||||
#
|
||||
# Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
# distribute this software, either in source code form or as a compiled
|
||||
# binary, for any purpose, commercial or non-commercial, and by any
|
||||
# means.
|
||||
#
|
||||
# In jurisdictions that recognize copyright laws, the author or authors
|
||||
# of this software dedicate any and all copyright interest in the
|
||||
# software to the public domain. We make this dedication for the benefit
|
||||
# of the public at large and to the detriment of our heirs and
|
||||
# successors. We intend this dedication to be an overt act of
|
||||
# relinquishment in perpetuity of all present and future rights to this
|
||||
# software under copyright law.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
# OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# For more information, please refer to <http://unlicense.org/>
|
||||
#
|
||||
# ###
|
||||
#
|
||||
# btw depends these packages:
|
||||
# `acpi` ; <https://sourceforge.net/projects/acpiclient/>
|
||||
# `libnotify` ; <https://salsa.debian.org/gnome-team/libnotify>
|
||||
#
|
||||
# Installation:
|
||||
# Arch Linux:
|
||||
# # pacman -S acpi (commynity repo)
|
||||
# # pacman -S libnotyfy (extra repo)
|
||||
# Debian/Ubuntu:
|
||||
# # apt-get install acpi
|
||||
# # apt-get install libnotify
|
||||
|
||||
btw_ver() {
|
||||
echo btw 1.0; exit 0
|
||||
}
|
||||
|
||||
btw_help() {
|
||||
cat <<- 'EOF'
|
||||
btw - Battery Watchdog. Send notification if critical battery level reached.
|
||||
|
||||
Usage: btw [-v|--version] [-h|--help] [-c|--crit <val>]
|
||||
[-p|--preriod <seconds>] [-l|--log <file>]
|
||||
[-s|--summary <summary>] [-b|--body <body>] [-w|--watch]
|
||||
|
||||
Options:
|
||||
-v, --version print version and exit.
|
||||
-h, --help print this help message and exit.
|
||||
-c, --crit <val> battery critical value (in percents), default: 10
|
||||
-p, --preriod <seconds> battery check out period in seconds, default: 30
|
||||
-l, --log <file> log file, default: ~/.cache/btwatchdog.log
|
||||
-s, --summary <summary> custom notification title text.
|
||||
-b, --body <body> custom notification body text.
|
||||
-w, --watch follow to log file ('tail -f'), use '--log' to
|
||||
set log file path.
|
||||
|
||||
Run watchdog in background. See application autostart options for your desktop
|
||||
environment. For example:
|
||||
|
||||
Add to your '~/.xinitrc':
|
||||
btw &
|
||||
|
||||
or create '~/.config/autostart/btw.desktop' if you have GNOME Desktop:
|
||||
[Desktop Entry]
|
||||
Name=Laptop battery watchdog (btw)
|
||||
Exec=btw
|
||||
Type=Application
|
||||
|
||||
Logging
|
||||
|
||||
btw writes battery status log in log file. Set file by '--log' option.
|
||||
Log format: '[date time] [state] [level]%'
|
||||
There is: [date time] `date +'%Y-%m-%d %H:%M:%S'` command output.
|
||||
[state] battery status, can be 'Charging' or 'Discharging'.
|
||||
[level] battery current level in percents.
|
||||
|
||||
Notifications
|
||||
|
||||
btw will send notification at every battery checkout while current battery
|
||||
level in lower than critical value. For example, with command:
|
||||
btw --crit 10 --period 30
|
||||
you will recieve notification every 30 seconds until battery is under 10%.
|
||||
|
||||
You can set up custom notification text via '--summary' and '--body' options.
|
||||
Variables can be used in notification:
|
||||
level current battery level in percents.
|
||||
state current battery status.
|
||||
For example:
|
||||
btw --summary 'Battery is very low!' --body 'Status: ${state,,}, ${level}%'
|
||||
|
||||
License: The Unlicense <https://unlicense.org/>
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Default values.
|
||||
period=30 # check battery every `period` seconds
|
||||
critical=10 # battery limit (in %)
|
||||
clevel=100 # current battery value (in %, temporary)
|
||||
summary='Extremely low battery: ${level}%'
|
||||
body='Check the charger, currently is ${state,,}'
|
||||
|
||||
lock=/tmp/btwatchdog.lock # lock file
|
||||
log=$HOME/.cache/btwatchdog.log # log
|
||||
mkdir -p $HOME/.cache || { echo "Cannot write log file: $HOME/.cache" >&2; }
|
||||
|
||||
btw_notify() {
|
||||
notify-send --urgency=critical --icon=battery-empty --category=System \
|
||||
"$(eval echo "$summary")" "$(eval echo "$body")"
|
||||
}
|
||||
|
||||
btw_isdigit() {
|
||||
if [[ "$1" =~ [0-9]+ ]]; then
|
||||
return 0
|
||||
else
|
||||
echo 'Value is not integer!' >&2; exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Transform long options to short ones
|
||||
for arg in "$@"; do
|
||||
shift
|
||||
case "$arg" in
|
||||
--crit) set -- "$@" "-c" ;;
|
||||
--period) set -- "$@" "-p" ;;
|
||||
--log) set -- "$@" "-l" ;;
|
||||
--summary) set -- "$@" "-s" ;;
|
||||
--body) set -- "$@" "-b" ;;
|
||||
--watch) set -- "$@" "-w" ;;
|
||||
--help) set -- "$@" "-h" ;;
|
||||
--version) set -- "$@" "-v" ;;
|
||||
*) set -- "$@" "$arg";;
|
||||
esac
|
||||
done
|
||||
|
||||
# Parse short opts
|
||||
while getopts c:p:l:s:b:whv opt; do
|
||||
case "$opt" in
|
||||
c) btw_isdigit "$OPTARG"; critical="$OPTARG";;
|
||||
p) btw_isdigit "$OPTARG"; period="$OPTARG" ;;
|
||||
l) log="$OPTARG";;
|
||||
s) summary="$OPTARG";;
|
||||
b) body="$OPTARG";;
|
||||
w) watchdog=1;;
|
||||
h) btw_help;;
|
||||
v) btw_ver;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$watchdog" ]; then
|
||||
tail --follow "$log"
|
||||
exit "$?"
|
||||
fi
|
||||
|
||||
while true; do
|
||||
battery=$(acpi -b | awk '{print $3 " " $4}' | sed -E 's/,|%//g;')
|
||||
level=${battery##* } # e.g. "49" (in percents)
|
||||
state=${battery%% *} # e.g. "Charging"
|
||||
|
||||
if [ "$level" -lt "$critical" ]; then
|
||||
if [ ! -f "$lock" ]; then
|
||||
btw_notify
|
||||
touch "$lock"
|
||||
fi
|
||||
# Warn in every percent less
|
||||
if [ "$level" -lt "$clevel" ]; then
|
||||
btw_notify
|
||||
touch "$lock"
|
||||
clevel="$level"
|
||||
fi
|
||||
else
|
||||
[ -f "$lock" ] && rm "$lock"
|
||||
fi
|
||||
|
||||
echo "$(date +'%Y-%m-%d %H:%M:%S') ${state,,} ${level}%" >> "$log"
|
||||
sleep $period
|
||||
done
|
94
src/codes
Executable file
94
src/codes
Executable file
@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
codes_help() {
|
||||
cat <<- EOF
|
||||
Display ANSI escape sequences.
|
||||
|
||||
Usage: codes [-vha] [-f] [-16] [-256]
|
||||
|
||||
Options:
|
||||
-a, --all display all codes (default).
|
||||
-f, --format display text formatting sequences table.
|
||||
-16 display 8/16 ANSI color codes table.
|
||||
-256 display 88/256 ANSI color codes table.
|
||||
-h, --help print this help message and exit.
|
||||
-v, --version print version and license info and exit.
|
||||
|
||||
NOTE: Safe codes for Linux TTY and most other terminals are 8 colors,
|
||||
inverted color and bold. Support for other sequences depends on the terminal
|
||||
being used.
|
||||
EOF
|
||||
codes_ansi_helper
|
||||
exit 0
|
||||
}
|
||||
|
||||
codes_version() { echo codes v1.0.1; exit 0; }
|
||||
|
||||
codes_ansi_helper() {
|
||||
echo
|
||||
echo -e '<Esc> character can be set as \\e or \\033 or \\x1B'
|
||||
echo
|
||||
echo -e '16 colors and formatting control sequence is <Esc>[ColorNumberm'
|
||||
echo -e '256 foreground control sequence is <Esc>[38;5;ColorNumberm'
|
||||
echo -e '256 background control sequence is <Esc>[48;5;1mColorNumberm'
|
||||
echo
|
||||
echo -e '<Esc>[0m -- reset all attributes.'
|
||||
}
|
||||
|
||||
codes_ansi_format() {
|
||||
echo -e 'Set Reset'
|
||||
echo -e " 1 21 \e[1mBold\e[0m";
|
||||
echo -e " 2 22 \e[2mDim\e[0m"
|
||||
echo -e " 3 23 \e[3mItalic\e[0m"
|
||||
echo -e " 4 24 \e[4mUnderlined\e[0m"
|
||||
echo -e " 5 25 \e[5mBlinking\e[0m"
|
||||
echo -e " 7 27 \e[7mInverted\e[0m"
|
||||
echo -e " 8 28 \e[8mHidden \e[0m(hidden)"
|
||||
echo -e " 9 29 \e[9mStrike\e[0m"
|
||||
}
|
||||
|
||||
codes_ansi_16() {
|
||||
for fgbg in 3 9 4 10; do
|
||||
for color in {0..7}; do
|
||||
printf "\e[${fgbg}%sm %3s \e[0m" $color ${fgbg}${color}
|
||||
if [ $color == 7 ]; then echo -e ''; fi;
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
codes_ansi_256() {
|
||||
for fgbg in 38 48 ; do # Foreground / Background
|
||||
for color in {0..255} ; do # Colors
|
||||
# Display the color
|
||||
printf "\e[${fgbg};5;%sm %3s \e[0m" $color $color
|
||||
# Display 6 colors per lines
|
||||
if [ $((($color + 1) % 6)) == 4 ] ; then
|
||||
echo # New line
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
codes_ansi_all() {
|
||||
echo -e '\e[1mFORMATTING\e[0m'
|
||||
codes_ansi_format
|
||||
echo -e '\n\e[1m8/16 COLORS\e[0m'
|
||||
codes_ansi_16
|
||||
echo -e '\n\e[1m88/256 COLORS\e[0m'
|
||||
codes_ansi_256
|
||||
codes_ansi_helper
|
||||
}
|
||||
|
||||
[[ "$@" ]] || codes_ansi_all
|
||||
|
||||
while (( "$#" )); do
|
||||
case "$1" in
|
||||
-a|--all) codes_ansi_all; exit 0;;
|
||||
-f|--format) codes_ansi_format; exit 0;;
|
||||
-16|--16) codes_ansi_16; exit 0;;
|
||||
-256|--256) codes_ansi_256; exit 0;;
|
||||
-h|--help) codes_help;;
|
||||
-v|--version) codes_version;;
|
||||
*) echo "${0##/*}: $1: bad option" >&2; exit 1;;
|
||||
esac
|
||||
done
|
138
src/currency
Executable file
138
src/currency
Executable file
@ -0,0 +1,138 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Favourites
|
||||
curr='USD|EUR|GBP|JPY|UAH'
|
||||
|
||||
# Get HTML-table with currencies in RUB from Russian Central Bank page.
|
||||
full_table="$(curl -sSL https://www.cbr.ru/currency_base/daily/ |
|
||||
sed "/<\/table>/,\$d" | tac | sed "/<table class/,\$d" | tac |
|
||||
dos2unix | tr '\n' ' ' | sed 's%>\s*<%><%g' | sed 's%</tbody>%%g' |
|
||||
sed 's%<tr>%\n%g;s%</tr>%%g' | sed 's%/%%g' |
|
||||
awk -F '<td>' '{print $2 " | " $4 " | " $6 " | " $8 " | " $10}')"
|
||||
|
||||
all_currencies_long() {
|
||||
echo "$full_table" |
|
||||
awk 'BEGIN {print "Цифр. код | Букв. код | Ед. | Валюта | Курс"}
|
||||
{print $0}' | column -t -s '|' | sed '2,3d'
|
||||
}
|
||||
|
||||
all_currencies() {
|
||||
echo "$full_table" |
|
||||
awk -F '|' '{print $2 " " $3 " " $5}' | column -t
|
||||
}
|
||||
|
||||
is_digit() {
|
||||
if [[ "$1" =~ [0-9]+ ]]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
is_currency() {
|
||||
if grep "^${1^^}$" <<< "$(all_currencies | awk '{print $1}')" > /dev/null; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
available_currencies() {
|
||||
all_currencies | cut -d ' ' -f 1 | sort | tr '\n' ' '
|
||||
}
|
||||
|
||||
calculate_rub() {
|
||||
_currency="$(all_currencies | grep "$currency" | awk '{print $3}' | sed 's%,%.%g')"
|
||||
_number="$(all_currencies | grep "$currency" | awk '{print $2}')"
|
||||
echo "(${_currency}/${_number})*${number}" | bc -l
|
||||
}
|
||||
|
||||
while getopts iIlahv OPT; do
|
||||
case "$OPT" in
|
||||
i) noninteractive=1;;
|
||||
I) interactive=1;;
|
||||
l) long=1;;
|
||||
a) all=1;;
|
||||
h) echo -e 'Get currencies from Russian Central Bank and calculate.\n\n' \
|
||||
'\bUsage: currency [-iIlahv] [<currency>] [<number>]\n' \
|
||||
'\bOptions:\n' \
|
||||
'\b -i non-interactive mode.\n' \
|
||||
'\b -I interactive mode.\n' \
|
||||
'\b -l print currencies in long format.\n' \
|
||||
'\b -a print all currencies.\n' \
|
||||
'\b -h print this help message and exit..\n' \
|
||||
'\b -v print version and exit..\n\n' \
|
||||
"\bAvailable currencies: $(available_currencies)"
|
||||
exit 0;;
|
||||
v) echo 'currency 1.1'; exit 0;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Parse positional arguments.
|
||||
shift $((OPTIND-1))
|
||||
|
||||
while (( "$#" )); do
|
||||
if is_currency "$1"; then
|
||||
currency="${1^^}"
|
||||
elif is_digit "$1"; then
|
||||
number="$1"
|
||||
else
|
||||
echo Invalid argument $1 >&2; exit 1
|
||||
fi
|
||||
shift
|
||||
done
|
||||
|
||||
if [ "$currency" ] && [ "$number" ]; then
|
||||
calculate_rub
|
||||
exit "$?"
|
||||
fi
|
||||
|
||||
if [ ! "$interactive" ]; then
|
||||
# Show currencies table
|
||||
if [ "$long" ]; then
|
||||
all_currencies_long | head -n 1
|
||||
if [ "$all" ]; then
|
||||
all_currencies_long | sed '1d'
|
||||
else
|
||||
all_currencies_long | grep -E "$curr"
|
||||
fi
|
||||
else
|
||||
if [ "$all" ]; then
|
||||
all_currencies
|
||||
else
|
||||
all_currencies | grep -E "$curr"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$noninteractive" ]; then
|
||||
exit 0
|
||||
else
|
||||
echo
|
||||
fi
|
||||
fi
|
||||
|
||||
# Interactive mode
|
||||
echo 'Specify currency and c.u. (^C for exit):'
|
||||
while true; do
|
||||
if [ "$currency" ]; then
|
||||
echo -n ">>> (${currency^^}) "
|
||||
read number
|
||||
if is_currency "$number"; then
|
||||
currency="${number^^}"; unset number
|
||||
elif ! is_digit "$number"; then
|
||||
echo Invalid number $number; unset number
|
||||
fi
|
||||
else
|
||||
echo -n ">>> "
|
||||
read currency
|
||||
if is_currency "$currency"; then
|
||||
currency="${currency^^}"
|
||||
else
|
||||
echo Invalid currency $currency; unset currency
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$number" ]; then
|
||||
calculate_rub
|
||||
fi
|
||||
done
|
174
src/dots
Executable file
174
src/dots
Executable file
@ -0,0 +1,174 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
version=0.3
|
||||
dots_conf_file=${HOME}/.dots.conf
|
||||
dots_local_repo=${HOME}/.local/share/dots
|
||||
unwanted_files=( .netrwhist )
|
||||
|
||||
# Color scheme
|
||||
R="\e[31m" # red
|
||||
G="\e[32m" # green
|
||||
Y="\e[33m" # yellow
|
||||
B="\e[94m" # light blue
|
||||
M="\e[95m" # light magenta
|
||||
C="\e[36m" # cyan
|
||||
Gr="\e[37m" # grey
|
||||
N="\e[0m" # no color
|
||||
b="\e[1m" # bold font
|
||||
|
||||
dots_version() {
|
||||
echo dots $version; exit 0
|
||||
}
|
||||
|
||||
dots_help() {
|
||||
cat <<- EOF
|
||||
Save and push dotfiles.
|
||||
|
||||
Usage: dots [-vh] command
|
||||
|
||||
Commands:
|
||||
save copy dotfiles to local repo (${dots_local_repo//$HOME\//\~\/})
|
||||
push commit and push dotfiles to remote git repo.
|
||||
show run 'git status' and print information about local repo.
|
||||
diff run 'git diff' in local repo.
|
||||
|
||||
Options:
|
||||
-v, --version print version and exit.
|
||||
-h, --help print this message and exit.
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
dots_init() {
|
||||
if [ -f "$dots_conf_file" ]; then
|
||||
: # do nothing
|
||||
else
|
||||
echo -e "${R}${dots_conf_file} doesn't exist\n" >&2
|
||||
echo -e "${dots_conf_file} content example:" >&2
|
||||
echo " .bashrc" >&2
|
||||
echo " .bash_aliases" >&2
|
||||
echo -e "${N}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -d "${dots_local_repo}/.git" ]; then
|
||||
: # do nothing
|
||||
else
|
||||
echo -e "${b}Init new ropository in${N} ${dots_local_repo}"
|
||||
mkdir -p "$dots_local_repo"
|
||||
echo -e "${B}; git init${N}"
|
||||
git init "$dots_local_repo"
|
||||
fi
|
||||
}
|
||||
|
||||
dots_clean() {
|
||||
# Remove confidential data from .bash* files.
|
||||
# `# Work` comment is trigger. Everything after this
|
||||
# comment to end of file will be deleted.
|
||||
|
||||
echo -e "\nClean up restricted data from ${b}.bash*${N} files ..."
|
||||
for bashfile in `find ${dots_local_repo} -type f -name ".bash*"`; do
|
||||
lnnum=`cat "$bashfile" | grep '# Work' -n | cut -d ':' -f 1`
|
||||
if grep '# Work' "$bashfile" > /dev/null; then
|
||||
echo "--> $bashfile"
|
||||
fi
|
||||
#echo "LN: $lnnum"
|
||||
if [ "$lnnum" != "" ]; then
|
||||
sed -i "${lnnum}q" "$bashfile"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
dots_remove_unwanted() {
|
||||
echo -e "${b}Remove unwanted files ...${N}"
|
||||
echo -e "${B}; find $dots_local_repo -name {...} -delete -print${N}"
|
||||
for unwanted in "${unwanted_files[@]}"; do
|
||||
find "$dots_local_repo" -name "$unwanted" -delete -print
|
||||
done
|
||||
}
|
||||
|
||||
dots_save() {
|
||||
dots_init
|
||||
|
||||
echo -e "${b}Copy dotfiles to repo${N}..."
|
||||
echo -e "${B}; cp --parents --recursive {...} ${dots_local_repo}${N}"
|
||||
for dotfile in $(cat "$dots_conf_file"); do
|
||||
cp --parents --recursive "${HOME}/${dotfile}" "${dots_local_repo}/"
|
||||
#echo -e "${G}${dotfile}${N}"
|
||||
done
|
||||
|
||||
dots_remove_unwanted # Remove unwanted files from local repo
|
||||
|
||||
echo -e "${B}; tree -a -F -I .git${N}"
|
||||
tree -a -F -I .git "$dots_local_repo"
|
||||
|
||||
dots_clean # Remove confidential data from local repo
|
||||
|
||||
echo -e "\nDone!"
|
||||
|
||||
echo -e "\n${b}Tips:${N}" \
|
||||
"\n Use ${M}${b}dots show${N} to run ${C}'git status'${N}" \
|
||||
"or ${M}${b}dots diff${N} to run ${C}'git diff'${N} in local repo." \
|
||||
"\n Use ${M}${b}dots push${N} to commit and push to remote repo."
|
||||
}
|
||||
|
||||
dots_push() {
|
||||
echo -e "${b}---${N}"
|
||||
echo -e "${B}; git add -A${N}"
|
||||
git -C "${dots_local_repo}" add -A
|
||||
echo -e "${B}; git commit -m 'Update dotfiles'${N}"
|
||||
git -C "${dots_local_repo}" commit -m 'Update dotfiles'
|
||||
|
||||
local remote="$(git -C "${dots_local_repo}" remote show)"
|
||||
if [ "$remote" == "" ]; then
|
||||
echo -e "${b}Add new remote server:${N}"
|
||||
echo -e \
|
||||
"Paste address like: ${Gr}git@github.com:user/repo.git${N} below:"
|
||||
while true; do
|
||||
read remote_addr
|
||||
if [[ "$remote_addr" =~ .*/.*\.git ]]; then
|
||||
break
|
||||
else
|
||||
echo "Please, re-enter remote address:"
|
||||
fi
|
||||
done
|
||||
echo -en "${B}; git remote add dots-repo ${remote_addr}${N} ... "
|
||||
git -C "${dots_local_repo}" remote add dots-repo "$remote_addr"
|
||||
echo -e "${G}${b}OK${N}"
|
||||
else
|
||||
: # do nothing
|
||||
fi
|
||||
|
||||
echo -e "${b}Processing${N}..."
|
||||
echo -e "${B}; git push dots-repo master${N}"
|
||||
git -C "${dots_local_repo}" push -u dots-repo master
|
||||
}
|
||||
|
||||
dots_show() {
|
||||
echo -e "${b}Config:${N} $dots_conf_file"
|
||||
echo -e "${b}Local repo:${N} $dots_local_repo"
|
||||
echo -e "${B}; git status${N}"
|
||||
git -C "$dots_local_repo" status
|
||||
}
|
||||
|
||||
dots_diff() {
|
||||
echo -e "${b}Config:${N} $dots_conf_file"
|
||||
echo -e "${b}Local repo:${N} $dots_local_repo"
|
||||
echo -e "${B}; git diff${N}"
|
||||
git -C "$dots_local_repo" diff "$@"
|
||||
}
|
||||
|
||||
[[ ! "$@" ]] && dots_help
|
||||
|
||||
while (( "$#" )); do
|
||||
case "$1" in
|
||||
save) shift; dots_save "$@"; shift "$#";;
|
||||
push) shift; dots_push "$@"; shift "$#";;
|
||||
show) shift; dots_show "$@"; shift "$#";;
|
||||
diff) shift; dots_diff "$@"; shift "$#";;
|
||||
-v|--version) dots_version ;;
|
||||
-h|--help) dots_help ;;
|
||||
-*) echo "$1: bad option" >&2; exit 1;;
|
||||
*) args+=("$1"); shift;;
|
||||
esac
|
||||
done
|
88
src/git-mass-clone
Executable file
88
src/git-mass-clone
Executable file
@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
print_help() {
|
||||
cat <<- EOF
|
||||
Clone and pull remote git repositories.
|
||||
|
||||
Usage: $0 [-fchv] <arguments>
|
||||
|
||||
Options:
|
||||
-f, --fetch-from <file> clone repositories listed in file.
|
||||
-c, --chdir <dir> change working directory [default: current]
|
||||
-h, --help print this help message and exit.
|
||||
-v, --version print version and exit.
|
||||
|
||||
Example of repository list file:
|
||||
|
||||
https://github.com/user/repo.git # my nice repo
|
||||
https://github.com/anothr_user/repo.git
|
||||
|
||||
Comments is allowed. Use hash (#) sign for comments.
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
[[ "$@" ]] || print_help
|
||||
|
||||
# Transform long options to short ones
|
||||
for arg in "$@"; do
|
||||
shift
|
||||
case "$arg" in
|
||||
--fetch-from) set -- "$@" "-f";;
|
||||
--chdir) set -- "$@" "-c";;
|
||||
--help) set -- "$@" "-h";;
|
||||
--version) set -- "$@" "-v";;
|
||||
*) set -- "$@" "$arg";;
|
||||
esac
|
||||
done
|
||||
|
||||
while getopts ":f:c:hv" opt; do
|
||||
case "$opt" in
|
||||
f) fetch_from="$OPTARG";;
|
||||
c) chdir="$OPTARG";;
|
||||
h) print_help;;
|
||||
v) echo 0.1; exit 0;;
|
||||
*) echo "Unknown option $opt" >&2; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$fetch_from" ]; then
|
||||
if test -f "$fetch_from"; then
|
||||
fetch_from="$(realpath "$fetch_from")"
|
||||
else
|
||||
echo "No such file $fetch_from" >&2; exit 1
|
||||
fi
|
||||
else
|
||||
echo "Missing argument for --fetch-from" >&2; exit 1
|
||||
fi
|
||||
|
||||
if [ "$chdir" ]; then
|
||||
chdir="$(realpath "$chdir")"
|
||||
else
|
||||
chdir="$PWD"
|
||||
fi
|
||||
|
||||
if [ -d "$chdir" ]; then
|
||||
:
|
||||
else
|
||||
echo "No such directory $chdir" >&2; exit 1
|
||||
fi
|
||||
|
||||
echo -e "Fetching git repos from $fetch_from to $chdir ..."
|
||||
echo -n 'Date: '; date -R
|
||||
git --version
|
||||
|
||||
sed 's/#.*//g;/^$/d' "$fetch_from" | while read repo; do
|
||||
echo -e "\nFETCHING $repo ..."
|
||||
echo '# ---------------------------------------------------------'
|
||||
repo_dir="${repo##*/}"
|
||||
repo_dir="${repo_dir//\.git}"
|
||||
repo_dir="$(realpath "${chdir}/${repo_dir}")"
|
||||
if git -C "$chdir" clone "$repo"; then
|
||||
:
|
||||
else
|
||||
echo "ENTERING INTO $repo_dir ..."
|
||||
cd "$repo_dir" && git pull && cd - >/dev/null ||
|
||||
{ echo "Cannot change dir to $OLDPWD" >&2; exit 1; }
|
||||
fi
|
||||
done
|
22
src/github-starred-repos
Executable file
22
src/github-starred-repos
Executable file
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Get user starred repos list.
|
||||
|
||||
# GitHub peronal access token (with restrictions: can read user info only)
|
||||
# https://docs.github.com/en/rest/guides/getting-started-with-the-rest-api#using-personal-access-tokens=
|
||||
personal_access_token=
|
||||
username=
|
||||
|
||||
# Get stars count
|
||||
stars=$(curl -sSI -u ${username}:${token} https://api.github.com/users/${username}/starred?per_page=1 |
|
||||
grep -i '^link:' | egrep -o 'page=[0-9]+' | tail -1 | cut -c6-)
|
||||
# Get pages count
|
||||
pages=$((stars/100+1))
|
||||
|
||||
{
|
||||
for page in `seq ${pages}`; do
|
||||
curl -sS -u ${username}:${token} \
|
||||
"https://api.github.com/users/${username}/starred?per_page=100&page=${page}" |
|
||||
jq -r '.[].clone_url'
|
||||
done
|
||||
}
|
110
src/http
Executable file
110
src/http
Executable file
@ -0,0 +1,110 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
http_version=0.5.1 # this script version.
|
||||
|
||||
set -o monitor # for job control.
|
||||
set -o errexit # exit if error occurs.
|
||||
|
||||
# Defaults
|
||||
HOST=0.0.0.0
|
||||
PORT=8000
|
||||
DIR=$PWD
|
||||
|
||||
# Check Python 3
|
||||
if ! hash python3 2>/dev/null; then
|
||||
echo -e "$0: Python 3 executable not found." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
http_print_help() {
|
||||
cat <<-EOF
|
||||
Run Python 3 builtin HTTP Server.
|
||||
|
||||
Usage: http [-v|--version] [-h|--help] [-c|--cgi] [-f|--firefox]
|
||||
[<host>[:<port>]] [<port>] [<dir>]
|
||||
|
||||
Options:
|
||||
-c, --cgi run as CGI Server.
|
||||
-f, --firefox open URL in Firefox.
|
||||
-h, --help print this help message and exit.
|
||||
-v, --version print version and exit.
|
||||
|
||||
Arguments:
|
||||
<host> host to bind. Default: 0.0.0.0
|
||||
<port> port to bind. Default: 8000
|
||||
<dir> directory to serve. Default: current directory.
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
while (( "$#" )); do
|
||||
case "$1" in
|
||||
-c|--cgi)
|
||||
CGI='--cgi';;
|
||||
-f|--firefox)
|
||||
FOX=1;;
|
||||
-h|--help)
|
||||
http_print_help;;
|
||||
-v|--version)
|
||||
echo "http v$http_version"; exit 0;;
|
||||
-*|--*)
|
||||
echo -e "$0: Bad option: $1" >&2
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
if [ -d "$1" ]
|
||||
then
|
||||
# If direcory exists set it as root DIR.
|
||||
DIR="$1"
|
||||
elif [[ "$1" =~ ^[0-9]+$ ]]
|
||||
then
|
||||
# If value is integer set it as PORT.
|
||||
PORT="$1"
|
||||
elif [[ "$1" =~ \
|
||||
^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]
|
||||
then
|
||||
# Value like IPv4 address. Not necessary.
|
||||
HOST="$1"
|
||||
elif [[ "$1" == 'localhost' ]]
|
||||
then
|
||||
# Nuff said.
|
||||
HOST="$1"
|
||||
elif [ "$(grep -o : <<<"$1")" ]
|
||||
then
|
||||
# If value like 'localhost:4000'
|
||||
HOST="$(echo "$1" | cut -d ":" -f 1)"
|
||||
PORT="$(echo "$1" | cut -d ":" -f 2)"
|
||||
else
|
||||
echo -e "$0: Bad option: $1$" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# Check available port and retry 3 times.
|
||||
retries=1
|
||||
while [ "$(ss -tanp | grep -o "$PORT")" ]; do
|
||||
if [[ "$retries" == 4 ]]
|
||||
then
|
||||
echo -e "Max number of retries reached! Exiting." >&2
|
||||
exit 1
|
||||
else
|
||||
:
|
||||
fi
|
||||
|
||||
# Increase port if is already in use.
|
||||
PORT_USED="$PORT"
|
||||
let PORT++
|
||||
echo -e "Port $PORT_USED is already in use!
|
||||
Switching to: $PORT" | sed 's/^ *//g' >&2
|
||||
|
||||
let retries++
|
||||
done
|
||||
|
||||
# Run Python http.server.
|
||||
echo -e "Serve: $DIR\tPress ^C to stop serving."
|
||||
python3 -m http.server $CGI --bind $HOST $PORT --directory $DIR &
|
||||
[[ "$FOX" == 1 ]] && firefox http://$HOST:$PORT/
|
||||
fg
|
95
src/log
Executable file
95
src/log
Executable file
@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env bash
|
||||
# Simple log viewing tool.
|
||||
|
||||
log_version=0.1
|
||||
|
||||
nginx_logs=/var/log/nginx
|
||||
exim4_logs=/var/log/exim4
|
||||
|
||||
print_help() {
|
||||
cat <<- EOF
|
||||
Print logs to STDOUT.
|
||||
|
||||
Usage: log [-vhtf] <log>
|
||||
|
||||
Options:
|
||||
-t [<num>], -<num> use tail with 'num' lines.
|
||||
-f, --tailf use 'tail -f'.
|
||||
-h, --help print this message and exit.
|
||||
-v, --version print version and exit.
|
||||
|
||||
Available logs (<log>):
|
||||
na nginx access logs ($nginx_logs)
|
||||
ne nginx error logs ($nginx_logs)
|
||||
ex exim4 logs ($exim4_logs)
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
print_log() {
|
||||
# Print logs to STDPUT with cat or zcat.
|
||||
|
||||
logfiles="$(sort -Vr <<< "$1")"
|
||||
|
||||
for logfile in $logfiles; do
|
||||
echo "* File: $logfile"
|
||||
if [[ "$(file --mime-type -b $logfile)" == application/gzip ]]
|
||||
then catzcat=zcat
|
||||
else catzcat=cat
|
||||
fi
|
||||
|
||||
"$catzcat" "$logfile"
|
||||
done
|
||||
}
|
||||
|
||||
tailf() {
|
||||
logfile="$(egrep -v '\.(1|gz)' <<< "$1")"
|
||||
tail -f "$logfile"
|
||||
}
|
||||
|
||||
parse_num() {
|
||||
arg="${1:1}"
|
||||
opt="$2"
|
||||
if [[ "$arg" =~ ^[0-9]+$ ]]; then
|
||||
num="$arg"; sft=1
|
||||
elif [[ "$arg" =~ ^t[0-9]+$ ]]; then
|
||||
num="${arg:1}"; sft=1
|
||||
elif [[ "$arg" == 't' ]] && [ "$opt" ]; then
|
||||
num="$opt"; sft=2
|
||||
else
|
||||
echo "$0: argument must be an integer" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Args pre-parser
|
||||
[[ "$@" ]] || print_help
|
||||
if [[ ! "$@" =~ na|ne|ex ]] && \
|
||||
[[ ! "$@" =~ -\h|--help|--version ]]; then
|
||||
echo -n "$0: no log name provided." >&2
|
||||
echo " See 'log --help' for info." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
while (( "$#" ))
|
||||
do
|
||||
case "$1" in
|
||||
na) logfiles="$(find "$nginx_logs" -type f -name "access*")";
|
||||
shift;;
|
||||
ne) logfiles="$(find "$nginx_logs" -type f -name "error*")";
|
||||
shift;;
|
||||
ex) logfiles="$(find "$exim4_logs" -type f)"
|
||||
shift;;
|
||||
-h|--help) print_help;;
|
||||
-v|--version) echo "log $log_version"; exit 0;;
|
||||
-f|--tailf) [ "$logfiles" ] && tailf "$logfiles";;
|
||||
-t|-t*|-[0-9]*) parse_num "$1" "$2"; shift "$sft";;
|
||||
*) echo "$0: bad argument: $1" >&2; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$num" ]; then
|
||||
print_log "$logfiles" | tail -n "$num"
|
||||
else
|
||||
print_log "$logfiles"
|
||||
fi
|
157
src/md2
Executable file
157
src/md2
Executable file
@ -0,0 +1,157 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
_md2_help() {
|
||||
cat <<- EOF
|
||||
Convert Markdown to different formats.
|
||||
|
||||
Usage: md2 [-v|-h] <command> [args]..
|
||||
md2 html <input> [<output>]
|
||||
md2 man <input> [<output>]
|
||||
md2 pdf <input> [<output>]
|
||||
|
||||
Options:
|
||||
-h, --help print this message and exit.
|
||||
-v, --version print version and exit.
|
||||
|
||||
Commands:
|
||||
html convert to HTML.
|
||||
man|roff convert to ROFF. Pass only <input> for preview.
|
||||
pdf convert to PDF.
|
||||
|
||||
Also you can use se symlbolic links to md2 to run commands.
|
||||
E.g.: symlink md2pdf -> md2 runs \`md2 pdf\`
|
||||
|
||||
md2 is just Pandoc wrapper. Edit md2 source code for customize.
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
_md2_usage() {
|
||||
echo "Usage: ${func:1} <input> [<output>]"
|
||||
[ "$func" == "_md2man" ] && \
|
||||
echo "Pass only <input> for preview."
|
||||
exit 0
|
||||
}
|
||||
|
||||
_md2_version() {
|
||||
cat <<- EOF
|
||||
md2 0.1.0
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
_md2() {
|
||||
# Wrapper function
|
||||
local inp out args preview
|
||||
|
||||
[[ ! "$@" ]] && _md2_usage
|
||||
|
||||
while (( "$#" )); do
|
||||
case "$1" in
|
||||
-h|--help) _md2_usage ;;
|
||||
-v|--version) _md2_version ;;
|
||||
-*) echo "${func:1}: $1: bad option." >&2
|
||||
_md2_usage ;;
|
||||
*) args+=("$1"); shift ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ ${#args[@]} -eq 2 ]; then
|
||||
inp="${args[0]}"; out="${args[1]}"
|
||||
elif [ ${#args[@]} -eq 1 ]; then
|
||||
inp="${args[0]}"; out="${args[0]%%.*}.${ext}"
|
||||
[ "$func" == "_md2man" ] && preview=1
|
||||
else
|
||||
_md2_usage
|
||||
fi
|
||||
|
||||
echo -e "\e[1mInput:\e[0m \e[37m${inp}\e[0m"
|
||||
|
||||
if [ "$preview" ]; then
|
||||
_md2man_preview "$inp"
|
||||
else
|
||||
echo -e "\e[1mOutput:\e[0m \e[37m${out}\e[0m"
|
||||
eval "$func" "$inp" "$out"
|
||||
fi
|
||||
}
|
||||
|
||||
_md2_run() {
|
||||
# Another wrapper function.
|
||||
case "$1" in
|
||||
-h|--help) _md2_help ;;
|
||||
-v|--version) _md2_version;;
|
||||
html) func=_md2html; ext='html'; shift;;
|
||||
man|roff) func=_md2man; ext='1'; shift;;
|
||||
pdf) func=_md2pdf; ext='pdf'; shift;;
|
||||
*) _md2_help ;;
|
||||
esac
|
||||
|
||||
_md2 "$@"
|
||||
exit $?
|
||||
}
|
||||
|
||||
# BEGIN Pandoc wrapper functions ##########################################
|
||||
|
||||
_md2html() {
|
||||
# HTML
|
||||
pandoc \
|
||||
--from=markdown \
|
||||
--to=html \
|
||||
--standalone \
|
||||
"$1" \
|
||||
--output="$2" \
|
||||
--variable document-css=true \
|
||||
--variable linkcolor='[HTML]{0000ff}' \
|
||||
--metadata title="${1%.*}"
|
||||
}
|
||||
|
||||
_md2man() {
|
||||
# ROFF
|
||||
pandoc \
|
||||
--from=markdown \
|
||||
--to=man \
|
||||
--standalone \
|
||||
"$1" \
|
||||
--output="$2"
|
||||
}
|
||||
|
||||
_md2man_preview() {
|
||||
# ROFF
|
||||
# View ROFF in pager without saving.
|
||||
pandoc --standalone --to man ${1:-"-"} | # Read into Pandoc
|
||||
groff -T utf8 -man | # format for pager.
|
||||
sed 1,4d | head -n -4 | # Chop off 4 leading/trailing
|
||||
# (empty) lines.
|
||||
less
|
||||
}
|
||||
|
||||
_md2pdf() {
|
||||
# PDF
|
||||
pandoc \
|
||||
--from=markdown-implicit_figures \
|
||||
--to=pdf \
|
||||
"$1" \
|
||||
--output="$2" \
|
||||
--pdf-engine=xelatex \
|
||||
--variable mainfont='FreeSans' \
|
||||
--variable fontsize='12pt' \
|
||||
--variable urlcolor='[HTML]{0000ff}' \
|
||||
--variable pagestyle=empty \
|
||||
--variable margin-left='20mm' \
|
||||
--variable margin-right='20mm' \
|
||||
--variable margin-top='20mm' \
|
||||
--variable margin-bottom='20mm' \
|
||||
--highlight-style haddock
|
||||
}
|
||||
|
||||
# END Pandoc wrapper functions ############################################
|
||||
|
||||
case "$0" in
|
||||
*md2) _md2_run "$@"; shift "$#" ;;
|
||||
*md2html) func=_md2html; ext='html' ;;
|
||||
*md2man) func=_md2man; ext='1' ;;
|
||||
*md2pdf) func=_md2pdf; ext='pdf' ;;
|
||||
*) echo "$0: bad command"; _md2_help;;
|
||||
esac
|
||||
|
||||
_md2 "$@"
|
121
src/mega
Executable file
121
src/mega
Executable file
@ -0,0 +1,121 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# ___ ___ __ __ __
|
||||
# /' __` __`\ /'__`\ /'_ `\ /'__`\
|
||||
# /\ \/\ \/\ \/\ __//\ \L\ \/\ \L\.\_
|
||||
# \ \_\ \_\ \_\ \____\ \____ \ \__/.\_\
|
||||
# \/_/\/_/\/_/\/____/\/___L\ \/__/\/_/
|
||||
# /\____/
|
||||
# \_/__/
|
||||
#
|
||||
# * MEGAcmd wrapper by ge
|
||||
# See more info about megacmd here: https://github.com/meganz/MEGAcmd
|
||||
#
|
||||
# This software is not affiliated with original MEGAcmd developers!
|
||||
#
|
||||
# * License: The Unlicense
|
||||
#
|
||||
# This is free and unencumbered software released into the public domain.
|
||||
#
|
||||
# Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
# distribute this software, either in source code form or as a compiled
|
||||
# binary, for any purpose, commercial or non-commercial, and by any
|
||||
# means.
|
||||
#
|
||||
# In jurisdictions that recognize copyright laws, the author or authors
|
||||
# of this software dedicate any and all copyright interest in the
|
||||
# software to the public domain. We make this dedication for the benefit
|
||||
# of the public at large and to the detriment of our heirs and
|
||||
# successors. We intend this dedication to be an overt act of
|
||||
# relinquishment in perpetuity of all present and future rights to this
|
||||
# software under copyright law.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
# OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# For more information, please refer to <http://unlicense.org/>
|
||||
|
||||
_mega_help_wrapper() {
|
||||
cat << 'EOF'
|
||||
|
||||
MEGAcmd wrapper script
|
||||
___ ___ __ __ __
|
||||
/' __` __`\ /'__`\ /'_ `\ /'__`\
|
||||
/\ \/\ \/\ \/\ __//\ \L\ \/\ \L\.\_
|
||||
\ \_\ \_\ \_\ \____\ \____ \ \__/.\_\
|
||||
\/_/\/_/\/_/\/____/\/___L\ \/__/\/_/
|
||||
/\____/
|
||||
\_/__/
|
||||
|
||||
Usage: mega command [<options>] [<arguments>]
|
||||
|
||||
mega is a megacmd wrapper that allows you to run megacmd commands as 'mega command'
|
||||
instead of 'mega-command'.
|
||||
|
||||
Wrapper commands:
|
||||
pid print mega-cmd-server pid
|
||||
ps show mega-cmd-server process
|
||||
tail 'tail -f $HOME/.megaCmd/megacmdserver.log'
|
||||
kill send SIGINT to mega-cmd-server process
|
||||
lsof lsof mega-cmd-server, pass output to PAGER if set
|
||||
[default: /usr/bin/less if exist or /usr/bin/more]
|
||||
Wrapper options:
|
||||
-h, -?, --help print this message, 'mega-help' output and exit.
|
||||
-u, --usage print only wrapper help message amd exit.
|
||||
Tips:
|
||||
mega cmd enter to MEGA shell
|
||||
mega quit stop MEGA server (mega-cmd-server)
|
||||
|
||||
@@@ This software is not affiliated with original MEGAcmd developers! @@@
|
||||
MEGAcmd User Guide: https://github.com/meganz/MEGAcmd/blob/master/UserGuide.md
|
||||
EOF
|
||||
if [ "$1" ]; then
|
||||
echo -e '\nSee available commands below (there is mega-help original output)'
|
||||
echo -e '\n---\n'
|
||||
mega-help
|
||||
else
|
||||
echo "Run 'mega help' or 'mega-help' to see available MEGAcmd commands."
|
||||
fi
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Select pager
|
||||
if [ -z "$PAGER" ]; then
|
||||
if [ -f /usr/bin/less ]; then
|
||||
PAGER=/usr/bin/less
|
||||
elif [ -f /usr/bin/more ]; then
|
||||
PAGER=/usr/bin/more
|
||||
else
|
||||
echo 'Pager not found! Use PAGER environment variable to set pager' >&2
|
||||
fi
|
||||
fi
|
||||
|
||||
[[ "$@" ]] || { _mega_help_wrapper 'with mega-help'; }
|
||||
# Add some additional commands
|
||||
case "$1" in
|
||||
-h|-\?|--help) _mega_help_wrapper 'with mega-help';;
|
||||
-u|--usage) _mega_help_wrapper;;
|
||||
pid) pgrep mega-cmd-server; exit "$?";; # check MEGA server
|
||||
ps) ps u -C mega-cmd-server; exit "$?";; # show MEGA server process
|
||||
tail) tail -f $HOME/.megaCmd/megacmdserver.log; exit "$?";;
|
||||
kill) killall -2 `pgrep mega-cmd-server`; exit "$?";;
|
||||
lsof) if [ "$PAGER" ]; then
|
||||
lsof -p `pgrep mega-cmd-server` | "$PAGER"
|
||||
else
|
||||
lsof -p `pgrep mega-cmd-server`
|
||||
fi
|
||||
exit "$?";;
|
||||
*) : # do nothing for another cases
|
||||
esac
|
||||
|
||||
_command="$1" # fetch command to execute
|
||||
shift # shift arguments to prevent running wrong commands like
|
||||
# 'mega-help help'
|
||||
|
||||
# Run command with arguments
|
||||
"mega-${_command}" "$@"
|
197
src/parts
Executable file
197
src/parts
Executable file
@ -0,0 +1,197 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#
|
||||
# * Parts
|
||||
#
|
||||
# Store and view your code snippets in files.
|
||||
#
|
||||
|
||||
partsversion=0.2
|
||||
[ "$PARTSPATH" ] || PARTSPATH=${HOME}/.local/share/parts
|
||||
[ -d "$PARTSPATH" ] || mkdir -p "$PARTSPATH" ||
|
||||
{ echo "Error: Cannot create PARTSPATH: $PARTSPATH"; exit 1; }
|
||||
parts=(`find "$PARTSPATH" -type f`)
|
||||
|
||||
pt_help() {
|
||||
cat <<- EOF
|
||||
Store and view code snippets (parts).
|
||||
|
||||
Usage: parts [-v| --version] [-h | --help] [-i | --interactive]
|
||||
[-a | --add <part>] [-l | --lang <language>]
|
||||
[-t | --tag <tag>] [-d | --descr <description>]
|
||||
[-r | --regex <regex>]
|
||||
|
||||
Options:
|
||||
-i, --interactive add a part in interactive mode.
|
||||
-a, --add <part> part text.
|
||||
-l, --lang <language> part's language.
|
||||
-t, --tag <tag> part's tag.
|
||||
-d, --descr <description> part description
|
||||
-r, --regex <regex> search part by regex (grep -P).
|
||||
-h, --help print this help message and exit.
|
||||
-v, --version print version and exit.
|
||||
|
||||
Environment variables:
|
||||
PARTSPATH
|
||||
path to save parts. Default: \$HOME/.local/share/parts
|
||||
PARTSHL
|
||||
code syntax highlighting. Depends 'highlight' package. Set
|
||||
the value of this variable to to enable, e.g. "1"
|
||||
EDITOR
|
||||
editor to be used in interactive mode.
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
pt_random() {
|
||||
local dict=({a..z} {A..Z} {0..9} - _)
|
||||
for i in {1..32}; do
|
||||
echo -n ${dict[$RANDOM%64]}
|
||||
done
|
||||
}
|
||||
|
||||
pt_interactive() {
|
||||
local _temp=`mktemp`
|
||||
local _edit="$EDITOR"
|
||||
local _partfile="${PARTSPATH}/`pt_random`.txt"
|
||||
cat > "$_temp" <<- EOF
|
||||
# Type your data between BEGIN and END comments.
|
||||
# DO NOT REMOVE COMMENTS!
|
||||
# See highlight(1) '--syntax' for Lang options.
|
||||
|
||||
# Part BEGIN
|
||||
|
||||
# Part END
|
||||
|
||||
# Lang BEGIN
|
||||
|
||||
# Lang END
|
||||
|
||||
# Tag BEGIN
|
||||
|
||||
# Tag END
|
||||
|
||||
# Descr BEGIN
|
||||
|
||||
# Descr END
|
||||
EOF
|
||||
"$_edit" "$_temp"
|
||||
|
||||
# Check file
|
||||
pt_parse_part "$_temp"
|
||||
[ "$partcode" ] || { echo Exited.; rm "$_temp"; exit 130; }
|
||||
|
||||
if cat "$_temp" > "$_partfile"; then
|
||||
echo -e "\e[1mSaved to:\e[0m $_partfile"
|
||||
rm "$_temp"
|
||||
else
|
||||
echo "Cannot write part. Saved to temporary file $_temp"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
pt_add() {
|
||||
local _partfile="${PARTSPATH}/`pt_random`.txt"
|
||||
cat > "$_partfile" <<- EOF
|
||||
# Type your data between BEGIN and END comments.
|
||||
# DO NOT REMOVE COMMENTS!
|
||||
# See highlight(1) '--syntax' for Lang options.
|
||||
|
||||
# Part BEGIN
|
||||
$partcode
|
||||
# Part END
|
||||
|
||||
# Lang BEGIN
|
||||
$partlang
|
||||
# Lang END
|
||||
|
||||
# Tag BEGIN
|
||||
$parttag
|
||||
# Tag END
|
||||
|
||||
# Descr BEGIN
|
||||
$partdescr
|
||||
# Descr END
|
||||
EOF
|
||||
[ -f "$_partfile" ] && { echo -e "\e[1mSaved to:\e[0m $_partfile"
|
||||
} || { echo "Cannot write part. Saved to temporary file $_temp"; exit 1; }
|
||||
}
|
||||
|
||||
pt_parse_part() {
|
||||
partcode="$(grep -zoP \
|
||||
'(?<=# Part BEGIN\n)(((.*)\n)*)(?=# Part END)' "$1" | tr -d '\0')"
|
||||
partlang="$(grep -zoP \
|
||||
'(?<=# Lang BEGIN\n)(((.*)\n)*)(?=# Lang END)' "$1" | tr -d '\0')"
|
||||
parttag="$(grep -zoP \
|
||||
'(?<=# Tag BEGIN\n)(((.*)\n)*)(?=# Tag END)' "$1" | tr -d '\0')"
|
||||
partdescr="$(grep -zoP \
|
||||
'(?<=# Descr BEGIN\n)(((.*)\n)*)(?=# Descr END)' "$1" | tr -d '\0')"
|
||||
}
|
||||
|
||||
pt_view_part() {
|
||||
pt_parse_part "$1"
|
||||
echo -e "\e[94m$1"
|
||||
[ "$partdescr" ] && echo -e "\e[94;1m+\e[0m \e[1m$partdescr\e[0m"
|
||||
[ "$parttag" ] && echo -e "\e[94;1m#\e[0m \e[1m$parttag\e[0m"
|
||||
echo -e '\e[0m'
|
||||
|
||||
if [ "$PARTSHL" ]; then
|
||||
[ "$partlang" ] || partlang=txt
|
||||
echo "$partcode" | highlight -O ansi -S "${partlang,,}"
|
||||
else
|
||||
echo "$partcode"
|
||||
fi
|
||||
echo
|
||||
}
|
||||
|
||||
pt_search_regex() {
|
||||
local _list="$(grep -Prl "$1" "$PARTSPATH")"
|
||||
[ "$_list" ] && {
|
||||
while read -r part; do
|
||||
pt_view_part "$part"
|
||||
done <<< "$_list"
|
||||
} || { echo -e "\e[91mNo matches for $1\e[0m"; exit 1; }
|
||||
}
|
||||
|
||||
#
|
||||
# * Args parser
|
||||
#
|
||||
|
||||
# Transform long options to short ones
|
||||
for arg in "$@"; do
|
||||
shift
|
||||
case "$arg" in
|
||||
--version) set -- "$@" "-v" ;;
|
||||
--help) set -- "$@" "-h" ;;
|
||||
--interactive) set -- "$@" "-i" ;;
|
||||
--add) set -- "$@" "-a" ;;
|
||||
--lang) set -- "$@" "-l" ;;
|
||||
--tag) set -- "$@" "-t" ;;
|
||||
--descr) set -- "$@" "-d" ;;
|
||||
--regex) set -- "$@" "-r" ;;
|
||||
*) set -- "$@" "$arg";;
|
||||
esac
|
||||
done
|
||||
|
||||
while getopts "vhia:l:t:d:r:" opt; do
|
||||
case "$opt" in
|
||||
v) echo parts $partsversion; exit 0;;
|
||||
h) pt_help;;
|
||||
i) pt_interactive;;
|
||||
a) partcode="$OPTARG";;
|
||||
l) partlang="$OPTARG";;
|
||||
t) parttag="$OPTARG";;
|
||||
d) partdescr="$OPTARG";;
|
||||
r) pt_search_regex "$OPTARG";;
|
||||
esac
|
||||
done
|
||||
|
||||
[[ "$@" ]] || {
|
||||
for _part in "${parts[@]}"; do
|
||||
pt_view_part "$_part"
|
||||
done
|
||||
}
|
||||
|
||||
[[ "$@" =~ -a|--add ]] && {
|
||||
pt_add
|
||||
}
|
47
src/rand
Executable file
47
src/rand
Executable file
@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
_count=1
|
||||
|
||||
rand_help() {
|
||||
cat <<- EOF
|
||||
Print random array item.
|
||||
|
||||
Usage: rand [-vhc] <arguments>...
|
||||
|
||||
Options:
|
||||
-c <count> print <count> random items [default: $_count]
|
||||
-h print this help message and exit.
|
||||
-v print version and exit.
|
||||
|
||||
Examples:
|
||||
$ rand duck chicken swan
|
||||
duck
|
||||
$ echo bee butterfly fly | xargs rand
|
||||
bee
|
||||
$ rand -c 36 {a..z} {A..Z} | xargs echo | sed 's% %%g'
|
||||
KAjcgyoANcEvNWDhkxuHlxJjFWDmVqglVGAZ
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
[[ "$@" ]] || rand_help
|
||||
|
||||
while getopts vhc: OPT; do
|
||||
case "$OPT" in
|
||||
v) echo rand 0.1; exit 0;;
|
||||
h) rand_help;;
|
||||
c) _count="$OPTARG";;
|
||||
esac
|
||||
done
|
||||
|
||||
shift "$((OPTIND-1))"
|
||||
|
||||
if [[ "$@" ]]; then
|
||||
_args=("$@")
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for (( i=0; i<"$_count"; i++ )); do
|
||||
echo ${_args[$(($RANDOM%${#_args[@]}))]}
|
||||
done
|
113
src/safeeject
Executable file
113
src/safeeject
Executable file
@ -0,0 +1,113 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -o errexit
|
||||
|
||||
print_help() {
|
||||
cat <<- EOF
|
||||
Safely remove an external drive. Unmount and power-off device via udisksctl.
|
||||
|
||||
Usage: safeeject [-hv] [<mountpoint>]
|
||||
|
||||
Options:
|
||||
-h print this help message and exit.
|
||||
-v print version and exit.
|
||||
EOF
|
||||
}
|
||||
|
||||
yesno() {
|
||||
local answer=
|
||||
[ "$ASSUME_YES" ] && return 0
|
||||
|
||||
while [ ! "$answer" ]; do
|
||||
echo -en "$@ (answer 'yes' to proceed) "
|
||||
read -r reply
|
||||
case "${reply,,}" in
|
||||
yes) answer=0;;
|
||||
*) answer=1;;
|
||||
esac
|
||||
done
|
||||
return "$answer"
|
||||
}
|
||||
|
||||
resolve_device() {
|
||||
case "$1" in
|
||||
/dev/sd*|/dev/hd*)
|
||||
local del="$(echo "$1" | grep -Po '(?<=[a-z])([0-9]+)$')";;
|
||||
/dev/nvme*)
|
||||
local del="$(echo "$1" | grep -Po '(?<=[0-9])?([a-z])([0-9]+)$')";;
|
||||
*)
|
||||
echo -e "\e[91mCannot parse device name\e[0m"; return;;
|
||||
esac
|
||||
echo "${1//$del}"
|
||||
}
|
||||
|
||||
while getopts hv OPT; do
|
||||
case $OPT in
|
||||
h) print_help; exit 0;;
|
||||
v) echo 1.1; exit 0;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND-1))
|
||||
point="$1"
|
||||
|
||||
if [[ "$UID" != 0 ]]; then
|
||||
echo -e "\e[91mYou arn't root!\e[0m" >&2; exit 1
|
||||
fi
|
||||
|
||||
if ! hash udisksctl &>/dev/null; then
|
||||
echo -e '\e[91mudisksctl utility not found!\e[0m' >&2; exit 1
|
||||
fi
|
||||
|
||||
[ "$point" ] || { echo -e '\e[91mNo mountpoint specified\e[0m'; exit 1; }
|
||||
|
||||
if [[ "$point" == '/' ]]; then
|
||||
echo -e '\e[91mCannot unmount root\e[0m'; exit 1
|
||||
fi
|
||||
|
||||
echo -e "Mountpoint: \e[1m${point%%/}\e[0m"
|
||||
|
||||
partition="$(mount | grep " ${point%%/} " | tee /dev/stderr | awk '{print $1}')"
|
||||
if [ "$partition" ]; then
|
||||
echo -e "Partition: \e[1m${partition}\e[0m"
|
||||
else
|
||||
echo -e "\e[91mNo filesystems mounted on ${point%%/}\e[0m"; exit 1
|
||||
fi
|
||||
|
||||
device="$(resolve_device "$partition")"
|
||||
echo -e "Device: \e[1m${device}\e[0m"
|
||||
if [[ ! "$device" =~ Cannot.* ]]; then
|
||||
fdisk --color=never --list "$device"
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Do not allow poweroff the system disk!
|
||||
root_partition="$(mount | grep " / " | tee /dev/stderr | awk '{print $1}')"
|
||||
root_device="$(resolve_device "$root_partition")"
|
||||
if [[ "$device" == "$root_device" ]]; then
|
||||
echo -e '\e[91mYou cannot eject primary disk!\e[0m'; exit 1
|
||||
fi
|
||||
|
||||
echo -e "\n\e[91mDo not continue if device is not detected correctly," \
|
||||
"instead unmount and poweroff the device manually!\e[0m"
|
||||
|
||||
if yesno "Is $device the correct device?"; then
|
||||
echo Sync to disk ...
|
||||
sync
|
||||
sleep 5
|
||||
echo Unmounting $partition ...
|
||||
if udisksctl unmount -b "$partition"; then
|
||||
sleep 1
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
echo Power off device $device ...
|
||||
if udisksctl power-off -b "$device"; then
|
||||
sleep 2
|
||||
echo -e '\e[92mNow you can safely eject device\e[0m'
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo Abort; exit 1
|
||||
fi
|
31
src/unflac
Executable file
31
src/unflac
Executable file
@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
unflac_usage() {
|
||||
echo 'Convert FLAC to MP3 320kbps with metadata via ffmpeg.'
|
||||
echo 'Usage: unflac [-h|--help] [-d|--delete] [<file>]'
|
||||
echo 'Options:'
|
||||
echo ' -h, --help print this message and exit.'
|
||||
echo ' -d, --delete delete original FLAC file after conversion.'
|
||||
echo 'For multiple files: for file in *; do unflac -d "$file"; done'
|
||||
}
|
||||
|
||||
[ "$1" ] || { unflac_usage; exit 0; }
|
||||
|
||||
while (( "$#" )); do
|
||||
case "$1" in
|
||||
-h|--help) unflac_usage; exit 0;;
|
||||
-d|--delete) delete_flac=1; shift;;
|
||||
-*) echo Unknown option $1 >&2; exit 1;;
|
||||
*) flac="$1"; shift;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -f "${flac//\.flac/\.mp3}" ]; then
|
||||
echo File \*.mp3 already exists!
|
||||
else
|
||||
echo -e "\e[30;102mFILE: $flac\e[0m";
|
||||
if ffmpeg -i "$flac" -ab 320k -map_metadata 0 -id3v2_version 3 "${flac//\.flac/}.mp3"; then
|
||||
echo OK
|
||||
[ "$delete_flac" ] && { echo -"Deleting original FLAC file: $flac"; rm -f "$flac"; }
|
||||
fi
|
||||
fi
|
323
src/upload
Executable file
323
src/upload
Executable file
@ -0,0 +1,323 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# upload
|
||||
#
|
||||
# Upload files to remote server. upl implements handy interface for
|
||||
# scp (OpenSSH secure file copy). upl cannot be called a full-fledged
|
||||
# frontend (or wrapper) for scp, since it does not allow changing the scp
|
||||
# parameters through its interface without editing the source code.
|
||||
#
|
||||
# Instead, upl implements the concept for accessing frequently used remote
|
||||
# servers. All you need to download is a short server name and filenames.
|
||||
# See more info in 'upl --help' (upl_help() function below).
|
||||
|
||||
upl_version=0.1.1
|
||||
upl_config=$HOME/.uploadrc
|
||||
|
||||
# Default values.
|
||||
#
|
||||
# Default destination dir. Can be set in $upl_config file
|
||||
# in server URI or passed as CLI argument.
|
||||
#
|
||||
destdir='~'
|
||||
# Default SCP commands.
|
||||
#
|
||||
# This is just templates for printf.
|
||||
#
|
||||
# If you have SSH keys:
|
||||
scp_cmd='scp -r %s %s'
|
||||
# If you use password:
|
||||
scp_cmd_pass='sshpass -p %s scp -r %s %s'
|
||||
|
||||
# HELP
|
||||
########
|
||||
|
||||
upl_help() {
|
||||
cat <<- EOF
|
||||
Upload files to remote server.
|
||||
|
||||
Usage: upload [-v|--version] [-h|--help] [-a|--aliases] [-p|--prompt]
|
||||
[-d|--dest=<path>] [<user@server:/path>]
|
||||
[<alias>] <files>...
|
||||
|
||||
Options:
|
||||
-d, --dest=<path> absolute path to destination dir on remote server.
|
||||
-a, --aliases print available server aliases and exit.
|
||||
-p, --prompt show uploading confirmation prompt.
|
||||
-v, --version print version and exit.
|
||||
-h, --help print this help message and exit.
|
||||
|
||||
How to:
|
||||
1. Create a config file named '.uploadrc' in your home directory. It should
|
||||
list servers with their aliases in the following format:
|
||||
<server alias> <user@server:/destination/dir> [<password>]
|
||||
Example:
|
||||
srv1 root@srv.example.com password
|
||||
srv2 admin@123.45.67.89:/uploads
|
||||
To upload testfile.txt to srv2 just run:
|
||||
upload srv2 testfile.txt
|
||||
|
||||
If you specify only one server in the file, then it will be used by default
|
||||
and you will not need to specify its alias when uploading files.
|
||||
|
||||
The URI address and destination directory specified in the command line
|
||||
override the data from the .uploadrc.
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
# CONFIG PARSER
|
||||
#################
|
||||
|
||||
upl_check_config() {
|
||||
# Return error if $upl_config not exists or is empty.
|
||||
if [ ! -f "$upl_config" ]; then
|
||||
echo "$0: $upl_config: file not exist" >&2; exit 1
|
||||
elif [ ! -s "$upl_config" ]; then
|
||||
echo "$0: no servers set in $upl_config" >&2; exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
upl_load_config() {
|
||||
# Load configuration from file.
|
||||
#
|
||||
# Check syntax and return $servers
|
||||
|
||||
# Remove comments from config.
|
||||
servers="$(sed '/^#/d;/^$/d;s/#.*//g' < "$upl_config")"
|
||||
|
||||
# Check syntax.
|
||||
local ln=0 # line number
|
||||
while read -r line
|
||||
do
|
||||
let ln++
|
||||
# Invalid URI.
|
||||
if [[ ! "$line" =~ \s*.+@.+ ]]; then
|
||||
echo "$0: $upl_config: URI is not set in line $ln" >&2
|
||||
exit 1
|
||||
fi
|
||||
# Parameters count.
|
||||
local words=$(wc -w <<< "$line")
|
||||
if [ $words -gt 3 ]; then
|
||||
echo "$0: $upl_config: too many params in line $ln" >&2
|
||||
exit 1
|
||||
elif [ $words -eq 1 ]; then
|
||||
echo "$0: $upl_config: invalid server entry in line $ln" >&2
|
||||
exit 1
|
||||
fi
|
||||
done <<< "$servers"
|
||||
}
|
||||
|
||||
upl_get_aliases() {
|
||||
# Collect server aliases.
|
||||
while read -r line
|
||||
do
|
||||
aliases+=("${line%% *}")
|
||||
done <<< "$servers"
|
||||
}
|
||||
|
||||
upl_set_destdir() {
|
||||
# Set up $destdir.
|
||||
#
|
||||
# Default value is '~'
|
||||
#
|
||||
# Arguments:
|
||||
# $1 -- URI string.
|
||||
if [[ "$1" =~ .+:.+ ]]; then
|
||||
local uri="${1##*:}" # '/path' from 'user@server:/path'
|
||||
fi
|
||||
|
||||
# Keep default value if destination dir is not set anywhere.
|
||||
if [[ ! "$destdir" = '~' ]]
|
||||
then
|
||||
: # That means '$destdir is set as CLI argument.'
|
||||
# Nothing to do. This has max priority.
|
||||
else
|
||||
if [ "$uri" ]; then destdir="$uri"; fi
|
||||
fi
|
||||
}
|
||||
|
||||
# FUNCTIONS
|
||||
#############
|
||||
|
||||
upl_show_list() {
|
||||
# Print table lines with server entries.
|
||||
#
|
||||
# Passwords will not shown.
|
||||
|
||||
local table_content="$(echo "$servers" |
|
||||
awk 'BEGIN {print "| " "Alias" " | " "URI" " |"}
|
||||
{print "| " $1 " | " $2 " |"}' |
|
||||
column -t
|
||||
)"
|
||||
|
||||
local table_border=$(\
|
||||
sed 's%|%+%g;s%[^+]%-%g;' <<< "$(head -n 1 <<< "$table_content")")
|
||||
|
||||
echo "$table_border"
|
||||
echo "$(head -n 1 <<< "$table_content")"
|
||||
echo "$table_border"
|
||||
echo "$(sed '1d' <<< "$table_content")"
|
||||
echo "$table_border"
|
||||
exit 0
|
||||
}
|
||||
|
||||
upl_yesno() {
|
||||
# "Yes|No" interactive dialog.
|
||||
#
|
||||
# Return exit code 0 or 1.
|
||||
local question="$1" # message
|
||||
local yes=0
|
||||
local no=1
|
||||
local answer=2
|
||||
|
||||
while [ $answer -eq 2 ]
|
||||
do
|
||||
echo -en "$question [y/n] "
|
||||
read -r reply
|
||||
case "$reply" in
|
||||
y|Y|Yes|YES) answer=$yes;;
|
||||
n|N|No|NO) answer=$no;;
|
||||
*) echo 'Please, answer y or n';;
|
||||
esac
|
||||
done
|
||||
|
||||
return "$answer"
|
||||
}
|
||||
|
||||
# ARGS PARSER
|
||||
###############
|
||||
|
||||
upl_getopts() {
|
||||
# GNU-style CLI options parser.
|
||||
#
|
||||
# Parse --opt VAL and --opt=VAL options.
|
||||
# Requires 2 arguments: $1, $2.
|
||||
# Return:
|
||||
# $opt - option name.
|
||||
# $arg - option's value.
|
||||
# $sft - value for shift.
|
||||
|
||||
if [[ "$1" =~ .+=.+ ]]; then
|
||||
opt="${1%%=*}"; arg="${1#*=}"; sft=1
|
||||
elif [[ ! "$1" =~ .+=$ ]] && \
|
||||
[ "$2" ] && [ "${2:0:1}" != '-' ]
|
||||
then
|
||||
opt="$1"; arg="$2"; sft=2
|
||||
else
|
||||
opt="$1"
|
||||
if [[ "$1" =~ .+=$ ]]; then opt="${1:0: -1}"; fi
|
||||
echo "missing argument for: $opt" >&2; exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
upl_is_uri() {
|
||||
# Check URI pattern like user@server from string $1
|
||||
#
|
||||
# Return $is_uri
|
||||
is_uri=1
|
||||
|
||||
if [[ "$1" =~ .+@.+ ]]; then is_uri=0; fi
|
||||
return $is_uri
|
||||
}
|
||||
|
||||
# Load configuration
|
||||
upl_check_config
|
||||
upl_load_config # get $servers
|
||||
upl_get_aliases # get $aliases from $servers
|
||||
|
||||
[[ "$@" ]] || upl_help
|
||||
while (( "$#" ))
|
||||
do
|
||||
case "$1" in
|
||||
-p|--prompt) prompt=1; shift;;
|
||||
-a|--aliases) upl_show_list; shift;;
|
||||
-d|--dest|--dest=*)
|
||||
sft=1 # Set default shift value.
|
||||
upl_getopts "$1" "$2"
|
||||
destdir="$arg"
|
||||
shift "$sft";;
|
||||
-h|--help) upl_help;;
|
||||
-v|--version) echo "upl v$upl_version"; exit 0;;
|
||||
-*) echo "$0: bad option: $1" >&2; exit 1;;
|
||||
*)
|
||||
sft=1 # Set default shift value.
|
||||
|
||||
if [[ "${aliases[@]}" =~ "$1" ]] # is server alias?
|
||||
then
|
||||
server_alias="$1"
|
||||
elif upl_is_uri "$1" # is user@server URI?
|
||||
then
|
||||
server_uri="$1";
|
||||
if [ "$2" ] && [ "${2:0:1}" != '-' ]; then
|
||||
ARGS+=("$2"); sft=2
|
||||
fi
|
||||
else
|
||||
ARGS+=("$1"); # collect positional arguments.
|
||||
fi
|
||||
shift "$sft";;
|
||||
esac
|
||||
done
|
||||
|
||||
# Exit if no servers found in $upl_conf file.
|
||||
if [ -z "$servers" ]; then
|
||||
echo "$0: $upl_config: no server entries found" >&2; exit 1
|
||||
fi
|
||||
|
||||
# Exit if server alias is not set.
|
||||
if [ "${#aliases[@]}" -gt 1 ] && \
|
||||
[ ! "$server_alias" ] && \
|
||||
[ ! "$server_uri" ]
|
||||
then
|
||||
echo "Please, specify server alias as argument or pass URI." >&2
|
||||
echo "Run 'upload -a' to see available aliases." \
|
||||
"See 'upload --help' for more." >&2
|
||||
exit 1
|
||||
elif [ "${#aliases[@]}" -eq 1 ] && \
|
||||
[ ! "$server_uri" ]
|
||||
then
|
||||
# Use single alias as default.
|
||||
server_alias=${servers%%* }
|
||||
fi
|
||||
|
||||
# Get basic data: URI and destination dir.
|
||||
server_entry=($(grep "$server_alias" <<< "$servers"))
|
||||
[ "$server_uri" ] || server_uri=${server_entry[1]}
|
||||
upl_set_destdir "$server_uri"
|
||||
|
||||
if [ "$prompt" ]; then
|
||||
echo "Uploading to..."
|
||||
echo
|
||||
echo "Remote server: $server_uri"
|
||||
echo "Destination dir: $destdir"
|
||||
echo "Files to upload:"
|
||||
echo -en ' '
|
||||
echo -e "${ARGS[@]}" | fmt -t
|
||||
echo
|
||||
if upl_yesno "Do you want to continue?"
|
||||
then echo # just print new line
|
||||
else echo Abort; exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Required data.
|
||||
#
|
||||
# There is:
|
||||
# | user@server:/path | password | file list
|
||||
reqs="${server_uri%%:*}:$destdir ${server_entry[2]} ${ARGS[@]}"
|
||||
|
||||
# Get upload command.
|
||||
if [ "${server_entry[2]}" ]; then
|
||||
upload_cmd="$(echo "$reqs" |
|
||||
awk '{print "sshpass -p " $2 " scp -r "}
|
||||
{for(i=3;i<=NF;i++){printf "%s ", $i}}
|
||||
{print " " $1}' | tr -d '\n')"
|
||||
else
|
||||
upload_cmd="$(echo "$reqs" |
|
||||
awk '{print "scp -r "}
|
||||
{for(i=2;i<=NF;i++){printf "%s ", $i}}
|
||||
{print " " $1}' | tr -d '\n')"
|
||||
fi
|
||||
|
||||
# Upload files!
|
||||
eval "$upload_cmd"
|
70
src/view
Executable file
70
src/view
Executable file
@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
view_version=0.8
|
||||
|
||||
view_help() {
|
||||
cat <<- EOF
|
||||
Print highlighted text to STDOUT.
|
||||
|
||||
Usage: view [-vhpn] [<file>]
|
||||
|
||||
Options:
|
||||
-l, -p, --pager pass output to pager (less).
|
||||
-n, --lines show line numbers.
|
||||
-h, --help print this help message and exit.
|
||||
-v, --version print version and exit.
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
view_langdetect() {
|
||||
if [[ "$1" =~ .+\..+ ]]; then
|
||||
echo "${1##*.}"
|
||||
else
|
||||
# Lookup for shebang
|
||||
echo "$_file" | head -n 1 | cut -d ' ' -f 2 |
|
||||
sed 's%\#\!%%g' | xargs basename
|
||||
fi
|
||||
}
|
||||
|
||||
view_hl() {
|
||||
_file="$(cat "${1:-/dev/stdin}")"
|
||||
|
||||
if ! local lang=$(view_langdetect "$1"); then
|
||||
langsh=sh
|
||||
fi
|
||||
|
||||
case "$lang" in
|
||||
python|python2|python3|python3.*) lang=py;;
|
||||
esac
|
||||
|
||||
echo "$_file" | highlight -O ansi -S "$lang"
|
||||
}
|
||||
|
||||
if ! hash highlight 2>/dev/null; then
|
||||
echo "highlight executable not found" >&2; exit 1
|
||||
fi
|
||||
|
||||
# Do nothing if no arguments passed and no STDIN.
|
||||
[[ -t 0 && -z "$1" ]] && view_help
|
||||
|
||||
while (( "$#" )); do
|
||||
case "$1" in
|
||||
-v|--version) echo view $view_version; exit 0;;
|
||||
-h|--help) view_help;;
|
||||
-l|-p|--pager) _pager=1; shift;;
|
||||
-n|--lines) _lines=1; shift;;
|
||||
-pn|-np) _pager=1; _lines=1; shift;;
|
||||
-*) echo "Invalid option: $1" >&2; exit 1;;
|
||||
*) args+=("$1"); shift;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$_pager" ]; then
|
||||
_pager=" | less -R"
|
||||
[ "$_lines" ] && _pager_opts=" -N"
|
||||
else
|
||||
[ "$_lines" ] && _catn=" | cat -n"
|
||||
fi
|
||||
|
||||
eval view_hl "$args" "$_pager" "$_pager_opts" "$_catn"
|
89
src/yad
Executable file
89
src/yad
Executable file
@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
yad_version=0.1.2
|
||||
API_URL='https://cloud-api.yandex.net/v1/disk/public/resources/download?public_key='
|
||||
|
||||
yad_help() {
|
||||
cat <<- EOF
|
||||
Dowload file from Yandex.Disk cloud storage.
|
||||
|
||||
Usage: yad [-Vhdv] <link>
|
||||
|
||||
Options:
|
||||
-d get direct link.
|
||||
-v verbose output.
|
||||
-V, --version print version and exit.
|
||||
-h, --help print this help message and exit.
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
[[ "$@" ]] || yad_help
|
||||
|
||||
while (( "$#" )); do
|
||||
case "$1" in
|
||||
-V|--version) echo "$yad_version"; exit 0;;
|
||||
-h|--help) yad_help;;
|
||||
-*)
|
||||
for i in $(seq 2 ${#1}); do opts+=("-${1:i-1:1}"); done
|
||||
|
||||
for opt in "${opts[@]}"; do
|
||||
case "$opt" in
|
||||
-d) direct_only=1;;
|
||||
-v) verbose=1;;
|
||||
*) echo "$0: Bad option: $opt" >&2; exit 1;;
|
||||
esac
|
||||
done
|
||||
shift;;
|
||||
*)
|
||||
if [[ ! "$1" =~ https://(disk.yandex.ru|yadi.sk)/.+/.+ ]]
|
||||
then
|
||||
echo "$0: Bad link: $1" >&2; exit 1
|
||||
fi
|
||||
share_link+=("$1")
|
||||
if [ ${#share_link[@]} -ne 1 ]; then
|
||||
echo "$0: Too many arguments" >&2; exit 1
|
||||
fi
|
||||
shift;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ ${#share_link[@]} -eq 0 ]; then
|
||||
echo "$0: No share link specified." >&2; exit 1
|
||||
fi
|
||||
|
||||
# Check the share link availability.
|
||||
response=$(curl -sSw %{http_code} -o /dev/null "$share_link")
|
||||
[ "$verbose" ] && echo "Responce code: $response"
|
||||
if [[ ! "$response" =~ 200|302 ]]; then
|
||||
echo "$0: Bad link: $share_link" >&2; exit 1
|
||||
fi
|
||||
|
||||
[ "$verbose" ] && {
|
||||
echo "Share link: $share_link"
|
||||
echo "API Request URL: ${API_URL}${share_link}"
|
||||
}
|
||||
|
||||
# Get direct URL from Yandex Public API.
|
||||
direct_link="$(python3 -c \
|
||||
"import json
|
||||
dl = json.loads('$(curl -sS "${API_URL}${share_link}")')
|
||||
print(dl['href'])"
|
||||
)"
|
||||
|
||||
[ "$verbose" ] && echo "Direct link: $direct_link"
|
||||
|
||||
if [ "$direct_only" ]; then
|
||||
echo "$direct_link"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Download file.
|
||||
file_name="$(grep -oP '(?<=filename\=).+(?=&disposition)' <<< "$direct_link")"
|
||||
|
||||
[ "$verbose" ] && {
|
||||
echo "File name: $file_name"
|
||||
curl_opts='-v'
|
||||
}
|
||||
|
||||
curl -L "$curl_opts" "$direct_link" -o "$file_name"
|
Loading…
Reference in New Issue
Block a user