#!/bin/bash
# This script makes a BTRFS subvolume with latest Archlinux iso image and sets a new entry in GRUB menu
# which allows you to boot from iso image directly. Some kind of RescueDisk that hard to broke
# because it is not mounted in your daily work routine. Feel free to run this script once a month,
# script will update the iso image to the latest from the mirror.
# Requires: BTFRS, GRUB, curl, grep, sed, sha256sum, tee, cat, find
mirror="mirror.ams1.nl.leaseweb.net" # More mirrors can be found here: https://archlinux.org/download/
subvol="@archiso"
iso="archlinux-x86_64.iso"
folder="/mnt/archiso"
rootdrive=$(mount | grep -Po '^.*(?= on \/ type btrfs)')
[ "$rootdrive" == "" ] && echo "This script works only with BTRFS" && exit 1
[ ! -e /etc/default/grub ] && echo "This script works only with GRUB" && exit 1
function writetogrub(){
sudo sed -i 's/GRUB_TIMEOUT=0/GRUB_TIMEOUT=1/' /etc/default/grub # At least one second needed
cat << EOF > /tmp/40_custom
menuentry 'Boot from archlinux.iso' {
load_video
set gfxpayload=keep
insmod gzio
insmod part_gpt
insmod btrfs
insmod loopback
probe -u \$root --set=rootuuid
set imgdevpath="/dev/disk/by-uuid/\$rootuuid"
set isofile='/@archiso/archlinux-x86_64.iso'
loopback loop \$isofile
linux (loop)/arch/boot/x86_64/vmlinuz-linux img_dev=\$imgdevpath img_loop=\$isofile earlymodules=loop
initrd (loop)/arch/boot/x86_64/initramfs-linux.img
}
EOF
if [ "$(wc -l < /etc/grub.d/40_custom)" -eq 5 ]; then
cat /tmp/40_custom | sudo tee -a /etc/grub.d/40_custom > /dev/null && sudo grub-mkconfig -o /boot/grub/grub.cfg
find /tmp/40_custom -delete
fi
}
function checkiso(){
curl -s "https://$mirror/archlinux/iso/latest/sha256sums.txt" | grep $iso | sha256sum -c -- || exit 5
}
if [ "$(sudo btrfs subvolume list / | grep 'top level [0-9] path '$subvol)" == "" ]; then
sudo mount "$rootdrive" /mnt
pushd "/mnt" > /dev/null && sudo btrfs subvolume create $subvol && popd > /dev/null /
sudo umount /mnt && writetogrub || echo "Error of creating $subvol!"
fi
if [ "$(sudo btrfs subvolume list / | grep 'top level [0-9] path '$subvol)" != "" ]; then
sudo mkdir -p $folder && sudo mount -o compress=zstd:3,subvol=$subvol "$rootdrive" $folder
pushd "$folder" > /dev/null || exit 2
if checkiso; then
echo "The latest Archlinux iso image already exists on the system. Nothing to do."
else
echo "Downloading $iso from $mirror to $HOME..."
builtin cd "$HOME" || exit 3
curl -L -O -C - "https://$mirror/archlinux/iso/latest/$iso"
sudo curl -o "$folder/$iso" "FILE:///home/$(whoami)/$iso"
checkiso && find "$HOME"/$iso -delete || echo "Checksum error!"
fi
builtin cd / && sudo umount $folder && sudo find $folder -delete
popd > /dev/null || exit 2
fi
#!/bin/bash
gitaurfolder=$HOME/.cache/aurgits
function print_help {
underline=$(tput smul)
nounderline=$(tput rmul)
echo "
Check source version for -git packages installed from AUR. Support local installed packages or repoctl
${underline}Usage${nounderline}: ${0##*/} [OPTIONS] [repoctl]
${underline}Options${nounderline}:
-h Print help information
-u Print URL source for updates
-b Build updates. Default option for makepkg is '-rfs' or can be added, e.g. '-b rsCc'
-q Supress info, show info about updates only
-c Clean cache folder after checking
${underline}Modes${nounderline}:
* Check installed packages. Default mode
repoctl Check packages at you own repository
"
}
function cleanfolder (){
if [ -n "$clean" ]; then
[ -z "$lessinfo" ] && echo -e "\nCleaning cache..."
find "$gitaurfolder" -delete
fi
}
function checkaurgit (){
if [ "$1" == "repoctl" ]; then
mapfile -t gitpackages < <(repoctl list | grep "git")
mapfile -t gitpackageversions < <(repoctl list -v | grep "git" | cut -d " " -f2)
else
mapfile -t gitpackages < <(pacman -Qq | grep "\-git$")
mapfile -t gitpackageversions < <(pacman -Q | grep "\-git " | cut -d " " -f2)
fi
[ ! -d "$gitaurfolder" ] && mkdir "$gitaurfolder"
pushd "$gitaurfolder" > /dev/null || exit 1
for index in ${!gitpackages[*]}; do
gitpackage=${gitpackages[$index]}
gitpackageversion=${gitpackageversions[$index]}
[ -z "$lessinfo" ] && echo -e "\nChecking package: $gitpackage"
[ ! -d "$gitpackage" ] && git clone --quiet "https://aur.archlinux.org/$gitpackage.git" 2> /dev/null
builtin cd "$gitpackage" || exit 2
mapfile -t giturl < <(grep -Po '(?<=git\+)http.*' .SRCINFO | sed 's|#branch=| -b |')
[ ! -d "${gitpackage%-git}" ] && git clone --quiet "${giturl[@]}" "${gitpackage%-git}" 2> /dev/null
builtin cd "${gitpackage%-git}" || exit 3
git pull --quiet
gitversion=$(
set -euo pipefail;
git describe --long --tags --abbrev=7 2>/dev/null | sed 's/\([^-]*-g\)/r\1/;s/-/./g;s/^v//' \
|| printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
)
if [[ ! "$gitpackageversion" =~ ${gitversion: -6} ]]; then
echo "$gitpackage ${gitpackageversion%-*} -> $gitversion"
[ -n "$show_url" ] && [ -z "$lessinfo" ] && grep -Po '(?<=url = ).*' ../.SRCINFO
updpackages+=("$gitpackage")
else
[ -z "$lessinfo" ] && echo "Version ${gitpackageversion%-*} is up to date"
fi
builtin cd "$gitaurfolder" || exit 2
done
popd > /dev/null || exit 1
}
while getopts ':hub:qc' option; do
case "$option" in
h ) print_help; exit 0;;
u ) show_url="y";;
b ) mkpgoptions="-$OPTARG";;
q ) lessinfo="y";;
c ) clean="y";;
: ) mkpgoptions="-rfs";;
\? ) [ -n "$OPTARG" ] && { echo "Option not found, try -h" && exit 1; }
esac
done
shift $((OPTIND - 1))
if [ "$1" == "repoctl" ] || [ "$mkpgoptions" == "-repoctl" ]; then
[ -x /usr/bin/repoctl ] && checkaurgit repoctl || echo "Repoctl not installed. Exiting..."
else
checkaurgit
fi
if [ -n "$mkpgoptions" ]; then
[ "$mkpgoptions" == "-repoctl" ] && mkpgoptions="-rfs"
for package in "${updpackages[@]}" ; do
pushd "$gitaurfolder/$package" > /dev/null || exit 1
echo -e "\nBuild $package with options $mkpgoptions"
if makepkg "$mkpgoptions" && [ -x /usr/bin/repoctl ]; then
read -n 1 -p "Add package to repository? [Y/n] " -r reply
[ "$reply" != "" ] && echo
if [ "$reply" = "${reply#[Nn]}" ]; then
find ! -name '*debug*' -name '*.pkg.tar.zst' -exec repoctl add {} \;
fi
fi
popd > /dev/null || exit 1
done
fi
cleanfolder
[ $# -gt 1 ]
]]>What's "test $2" for?
To see if you accidentally put a second argument. Is there a more idiomatic way to do that?
I'm also curious why you're deliberately downloading an html (and thus larger) version of the RFCs only to require a browser to then render this html as plain text ... just use the plain text source in the first place (e.g., ietf.org/rfc/rfc####) and open it in an editor or pager rather than a browser.
Some of the HTML versions have links to sections in their table of contents. I was about to point out that they also link to other RFCs, but those are local links so they wouldn't work. Hmm.
I don't mind the increased size, though; for comparison, RFC 1337 is 36K vs. 24K. Compression would probably make a bigger difference.
I'm non-committal about this, though. Plaintext might be neater.
]]>usage() {
echo 'Usage: rfc (NUMBER)'
echo Fetches rfc pages from rfc-editor.org if not already saved.
exit
}
(( 10#${1} )) 2>/dev/null || usage
…
What's "test $2" for?
]]>#!/bin/bash
URLPREFIX='https://www.rfc-editor.org/rfc/rfc' # where the RFCs are
# (just append number to that url)
if echo "$1" | grep '^[0-9]+$' -Ev &>/dev/null || test "$2"; then
echo 'Usage: rfc (NUMBER)'
echo Fetches rfc pages from rfc-editor.org if not already saved.
exit
fi
RFCPATH="$HOME/.rfc-cache/$1.html"
if [[ ! -e "$RFCPATH" ]]; then
echo Not cached.
if ! curl -f "$URLPREFIX$1" >"$RFCPATH"; then
echo Could not download RFC "$1".
rm "$RFCPATH"
exit
fi
fi
lynx "$RFCPATH"
#!/bin/bash
TG_BOT_API_TOKEN=""
TG_BOT_CHAT_ID=""
if [ -z "$TG_BOT_CHAT_ID" ]; then
echo 'Please, define TG_BOT_CHAT_ID and TG_BOT_API_TOKEN first! See "chat":{"id":xxxxxxx string below from request: curl https://api.telegram.org/bot$TG_BOT_API_TOKEN/getUpdates'
exit 1
fi
MSG=$(echo "$@" | tr '\n' '[' | sed 's/ /%20/g;s/\[/%0A/g') #Urlencoding some simbols for curl
#/usr/bin/wget -qO- "https://api.telegram.org/bot$TG_BOT_API_TOKEN/sendMessage?chat_id=$TG_BOT_CHAT_ID&parse_mode=html&text=$@" 2>&1
/usr/bin/curl --no-progress-meter "https://api.telegram.org/bot$TG_BOT_API_TOKEN/sendMessage?chat_id=$TG_BOT_CHAT_ID&parse_mode=HTML&text=$MSG" 2>&1
I think you mean:
TOP=${1:-10}
Good point! Didn't know about that.
On top of this, there is absolutely no reason to pipe through several instances of awk, sort, cut, etc. Just use one properly.
I use this script for a couple years and noted that awk eat a lot of memory when executed, so main idea is to use awk as much less as possible.
Example of using:
$ topmem
MEMORY Top 10 processes SWAP
23.13M sshd:
18.76M systemd-journald
12.96M sinit
11.62M awk
11.50M systemd
9.75M systemd-udevd
9.25M systemd-networkd
8.50M systemd-timesyncd
8.50M systemd-logind
7.07M sslh:
90M MemTotal 0M SwapTotal
So, vice versa, script need to be rewrited without using awk.
But then going further, just spending a little time reading `man ps` you'd realize this whole script should just be one proper `ps` command (maybe two if you want one list each for RAM and swap use).
I already use ps for taking memory info, so it could be shorter but will look the same. Anyway, thanks for feedback!
]]>TOP=$([ -z $1 ] && echo 10 || echo $1)
I think you mean:
TOP=${1:-10}
(actually I think you mean "top=${1:-10}" but that's a style issue)
On top of this, there is absolutely no reason to pipe through several instances of awk, sort, cut, etc. Just use one properly.
But then going further, just spending a little time reading `man ps` you'd realize this whole script should just be one proper `ps` command (maybe two if you want one list each for RAM and swap use).
]]>#!/bin/bash
TOP=$([ -z $1 ] && echo 10 || echo $1)
declare -a mem=($(ps -e -orss=,args= | awk '{print $1 " " $2 }' | awk '{tot[$2]+=$1;count[$2]++} END {for (i in tot) {print tot[i],i,count[i]}}' | sort -n | tail -n $TOP | sort -nr | awk '{hr=$1/1024; printf("%13.2fM|%s", hr, $2)}' | tr '\n' ' '))
declare -a swp=($(cat /proc/*/status | grep -E 'VmSwap:|Name:' | grep -B1 'VmSwap' | cut -d':' -f2 | grep -v -- '--' | grep -o -E '[a-zA-Z0-9]+.*$' | cut -d' ' -f1 | xargs -n2 echo | sort -hrk2 | awk '{hr=$2/1024; if (hr>0) printf("%13.2fM|%s", hr,$1)}' | tr '\n' ' '))
printf "%-9s %35s %-9s %20s\n" "MEMORY" "Top $TOP processes " "SWAP" ""
for (( j=0; j<${#mem[@]}; j++ ));
do
printf "%9s %-35s %9s %-20s\n" $(echo ${mem[$j]} | sed 's/|/ /;s|usr/||;s|bin/||;s|lib/||;s|/||;s|systemd/||') $(echo ${swp[$j]} | sed 's/|/ /')
done
echo
printf "%9s %-35s %9s %-20s\n" $(free -m | awk '/Mem/{print($3"M "$1)}'| sed 's/Mem:/MemTotal/') $(free -m | awk '/Swap/{print($3"M "$1)}' | sed 's/Swap:/SwapTotal/')
For example, if some service not started logger will show message about it.
#!/bin/bash
# https://wiki.archlinux.org/title/Systemd/Journal#Priority_level
## From 0: Emergency, 1: Alert, 2: Critical, 3: Error, 4: Warning, 5: Notice, 6: Informational, 7: Debug
LEVELTILL=3
SKIPWORDS="(TSC)" #messages about watchdog and other
OLDLOG=$HOME/.cache/oldjournal.log
NOWLOG=$HOME/.cache/journal.log
[ -z $OLDLOG ] || touch $OLDLOG
JRNLLOG=$(journalctl --no-pager -b0 -p$LEVELTILL | cut -d" " -f5- | grep -Ev $SKIPWORDS)
echo "$JRNLLOG" | sort | uniq -u > $NOWLOG
NOWDIFF=$(diff $OLDLOG $NOWLOG | grep -E '^>')
if [ "$NOWDIFF" != "" ]
then
echo -n " Changes in system journal:"
echo $NOWDIFF | tr ">" "\n" | sed -E 's/\[[0-9]+\]//g;s/ *$//g' | uniq
echo "$JRNLLOG" | sort |uniq -u > $OLDLOG
fi
And add this in .bashrc
if [ -n "$SSH_CLIENT" ] && [ -z "$TMUX" ]; then
if [ -f $HOME/scripts/logger.sh ]; then
echo -ne "\n";
$HOME/scripts/logger.sh
fi
fi
#!/bin/bash
# https://wiki.archlinux.org/title/Pacman/Tips_and_tricks#Packages_and_dependencies
## sudo pacman -Syu --needed expac
echo -e "\033[1mFrom repository:\033[0m"
expac -H M "%011m\t%-20n\t%10d" $(comm -23 <(pacman -Qqen | sort) <((expac -l '\n' '%E' base-devel; expac -l '\n' '%E' base) | sort -u))
[ -n "$(pacman -Qm)" ] && ( echo -e "\n\033[1mFrom AUR:\033[0m"; expac -H M "%011m\t%-20n\t%10d" $(pacman -Qqm) )
There are three methods of detecting, you could choose that works for you.
#!/bin/bash
DATE=$(/usr/bin/ls -ctl --time-style +"%Y-%m-%d" /etc | tail -1 | grep -Po "[0-9]+-[0-9]+-[0-9]+")
#or
#DATE=$(stat /etc | tail -1 | cut -d" " -f3)
#or
#DATE=$(head -1 /var/log/pacman.log | cut -c 2-11)
LOCALE=$(echo $DATE | sed 's/-/ /g' | awk '{print $3"."$2"."$1}')
DAYSBETWEEN=$(( ($(date -d $(date +%Y-%m-%d) +%s) - $(date -d $DATE +%s)) / 86400 ))
YEARSCALC=$(( $DAYSBETWEEN / 365 ))
MONTHSCALC=$(( ($DAYSBETWEEN - ($YEARSCALC * 365)) / 30 ))
DAYSCALC=$(( $DAYSBETWEEN -($YEARSCALC * 365) - ($MONTHSCALC * 30) ))
[[ $YEARSCALC > 0 ]] && YEARS=$YEARSCALC"y "
[[ $MONTHSCALC > 0 ]] && MONTHS=$MONTHSCALC"m "
[[ $DAYSCALC > 0 ]] && DAYS=$DAYSCALC"d"
echo "System age: "$YEARS$MONTHS$DAYS" (since $LOCALE)"