You are not logged in.
Small bash script to list all drives with their model names and serial numbers, as well as partition info via lsblk, combined in one:
#!/bin/bash
# ~/.local/bin/driveinfo -*- coding: utf-8-auto-unix -*-
# Shows useful info about connected block devices/drives
#------------------------------------------------------------------------------
print_deviceinfo() {
if [ "${#}" -lt 1 ]; then
echo "${FUNCNAME[0]}() requires 1 argument (/dev block device path)" >&2
return 1
fi
local DEV="$1"
if [ -b "$DEV" ]; then
if command -v 'udevadm' >/dev/null 2>&1; then
#sernum=$(smartctl -a "$DEV" | grep "Serial Number:" | cut -d ":" -f 2 | sed 's/\ //g')
sernum=$(udevadm info "$DEV" | cut -d " " -f "2-" | awk -F "=" '{ if ($1 == "ID_SERIAL") { print $2; } }')
echo "$DEV : $sernum"
else
echo "${FUNCNAME[0]}(): Error: 'udevadm' command not found!" >&2
return 1
fi
fi
return 0
}
MAXNUMBER=99
# /dev/nvmeXnY - NVMe SSD drives
for ((x = 0; x <= MAXNUMBER; x++)); do
for ((y = 0; y <= MAXNUMBER; y++)); do
print_deviceinfo "/dev/nvme${x}n${y}"
done
done
# /dev/sdX - SATA/SCSI drives
for x in {{a..z},{a..z}{a..z}}; do
print_deviceinfo "/dev/sd${x}"
done
# /dev/mmcblkX - SD/MMC cards / eMMC storage devices
for ((x = 0; x <= MAXNUMBER; x++)); do
print_deviceinfo "/dev/mmcblk${x}"
done
# /dev/srX - optical drives
for ((x = 0; x <= MAXNUMBER; x++)); do
print_deviceinfo "/dev/sr${x}"
done
# lsblk output
if command -v 'lsblk' >/dev/null 2>&1; then
echo ''
lsblk -o NAME,FSTYPE,SIZE,FSAVAIL,TYPE,HOTPLUG,MOUNTPOINT
fi
# blkid output
#if command -v 'blkid' >/dev/null 2>&1; then
# echo ''
# blkid
#fi
int pi = 3;
Offline
Small sh script to toggle mouse cursor highlighting on/off. Requires https://github.com/swillner/highlight-pointer. Useful for presentations.
#!/bin/sh
# ~/.local/bin/laserpointer.sh -*- coding: utf-8-auto-unix -*-
# Toggle script. Requires https://github.com/swillner/highlight-pointer
#------------------------------------------------------------------------------
if pgrep --full highlight-pointer >/dev/null 2>&1; then
echo "Stopping cursor highlight. To toggle on/off, run this script again."
killall highlight-pointer >/dev/null 2>&1
else
echo "Starting cursor highlight. To toggle on/off, run this script again."
#find-cursor --repeat 0 --follow --distance 0 --line-width 18 --size 18 --color green &
nohup highlight-pointer -c '#00ff00' -p '#3399ff' -o 0 -r 15 --show-cursor >/dev/null 2>&1 &
fi
int pi = 3;
Offline
Back in the day, network devices would have names like eth0 and wlan0, but that was apparently a problem, so they started having "reliable" names like "enp12s0" and "wlp14s0", but sometimes those names change too. I tried setting udev rules to manually name the devices, but that doesn't work, so the only thing left to do to ''reliably'' match a network device with a name that cannot be entirely known is to match by something that can: its mac address. To that end, I came up with this script (and call it from a systemd service at boot to connect my wifi):
#!/bin/bash
iw $(for mac in /sys/class/net/wlp*/address; do [[ $(cat $mac) == "$1" ]] && printf ${mac:15:7}; done) connect "$2"
where $1 is a mac address (ie, "a1:2b:c3:4d:e5:f6") and $2 is an access point
Last edited by quequotion (2021-08-22 01:01:18)
makepkg-optimize · indicator-powersave · pantheon-{3d,lite} · {pantheon,higan}-qq
Offline
Why don't you just put the MACAddress in the file, or use a drop in?
https://wiki.archlinux.org/title/Systemd-networkd#[Match]
Offline
Why don't you just put the MACAddress in the file, or use a drop in?
https://wiki.archlinux.org/title/Systemd-networkd#[Match]
I am doing that also:
cat /etc/systemd/network/20-wifi.network
[Match]
MACAddress=a1:2b:c3:4d:e5:f6
[Network]
Address=192.168.0.101
Gateway=192.168.0.1
DNS=127.0.0.1
This does not actually connect the wifi, though, it only ensures a correct ip setup in the local network when it gets connected.
Last edited by quequotion (2021-08-22 01:35:15)
makepkg-optimize · indicator-powersave · pantheon-{3d,lite} · {pantheon,higan}-qq
Offline
https://wiki.archlinux.org/title/Networ … face_names
The "reliable" names are simply the wrong choice for 99.8% of users who have one wired and maybe one wifi NIC.
Online
Worth reading thread about network naming rules:
https://bbs.archlinux.org/viewtopic.php?id=245428
I even made an aur package to ensure persistent network names, but in the end it is not that useful.
YMMV.
Last edited by kokoko3k (2021-08-22 12:40:12)
Help me to improve ssh-rdp !
Retroarch User? Try my koko-aio shader !
Offline
Girnel: A single-file, searchable journal for git repositories.
I wanted a way to be able to track my research alongside my code changes. This script appends new journal entries to a hidden .girnel file in the root of a git repository, and later parses that file to create a sqlite database searchable by author, date, time, branch, and commit.
I have the script under source control, so feel free to clone the repository if you would like to track updates.
#!/bin/bash
#
# ========
# GIRNEL
# ========
#
# Eric O Meehan
# 2021-08-26
#
# A simple, searchable journal for git repositories.
#
help()
{
echo "usage:"
echo " grnl <mode> 'input'"
echo " modes:"
echo " -r read (uses less to read .girnel)"
echo " -w write (opens vim to compose an entry)"
echo " -q query (opens a sqlite database)"
echo " input:"
echo " -w and -q accept a quoted argument to be used"
echo " as the girnel entry or sqlite query respectively"
}
declare -A PROJECT
GIRNEL=""
git_check()
{
if [[ $(git status 2> /dev/null) == "" ]]
then
echo "girnel requires a git repository"
exit 1
fi
}
girnel_check()
{
if [[ $(ls $GIRNEL 2> /dev/null) == "" ]]
then
echo ".girnel missing from project root"
exit 1
fi
}
setup()
{
git_check
PROJECT=(
['author']="$(git config user.name)"
['date']="$(date +%F)"
['time']="$(date +%H:%M:%S)"
['repository']="$(git rev-parse --show-toplevel)"
['branch']="$(git status | grep branch | cut -d ' ' -f3)"
['commit']="$(git rev-parse --short HEAD)"
)
GIRNEL="${PROJECT['repository']}/.girnel"
girnel_check
}
# Compose an Entry
compose()
{
touch /tmp/girnel
vim /tmp/girnel
ENTRY="$(cat /tmp/girnel)"
if [[ $ENTRY == "" ]]
then
echo "No body written, canceling entry."
exit 0
fi
}
write()
{
ENTRY="$(cat /tmp/girnel)"
rm /tmp/girnel
echo "========" >> $GIRNEL
echo "Author: ${PROJECT['author']}" >> $GIRNEL
echo "Date: ${PROJECT['date']}" >> $GIRNEL
echo "Time: ${PROJECT['time']}" >> $GIRNEL
echo "Branch: ${PROJECT['branch']}" >> $GIRNEL
echo "Commit: ${PROJECT['commit']}" >> $GIRNEL
echo "" >> $GIRNEL
echo "$ENTRY" >> $GIRNEL
echo "" >> $GIRNEL
echo "" >> $GIRNEL
}
# Query Previous Entries
DB_SCHEMA="CREATE TABLE entries (
entry_id INTEGER PRIMARY KEY NOT NULL,
author TEXT,
date TEXT,
time TEXT,
branch TEXT,
hash TEXT,
message TEXT NOT NULL
);"
declare -A ENTRY=(
['author']=""
['date']=""
['time']=""
['branch']=""
['commit']=""
['message']=""
)
insert()
{
sqlite3 /tmp/girnel.db "
INSERT INTO entries (
author, date, time, branch, hash, message
) VALUES (
\"${ENTRY['author']}\",
\"${ENTRY['date']}\",
\"${ENTRY['time']}\",
\"${ENTRY['branch']}\",
\"${ENTRY['commit']}\",
\"${ENTRY['message']}\"
);"
}
create_db()
{
touch /tmp/girnel.db
sqlite3 /tmp/girnel.db "$DB_SCHEMA"
while IFS='' read -r line || [ -n "${line}" ]
do
if [[ $line =~ "========" ]]
then
if [[ ${ENTRY['message']} != "" ]]
then
insert
ENTRY=(
['author']=""
['date']=""
['time']=""
['branch']=""
['commit']=""
['message']=""
)
fi
elif [[ $line =~ "Author:" ]]
then
ENTRY['author']=$(echo "$line" | cut -d ' ' -f2-)
elif [[ $line =~ "Date:" ]]
then
ENTRY['date']=$(echo "$line" | cut -d ' ' -f2-)
elif [[ $line =~ "Time:" ]]
then
ENTRY['time']=$(echo "$line" | cut -d ' ' -f2-)
elif [[ $line =~ "Branch:" ]]
then
ENTRY['branch']=$(echo "$line" | cut -d ' ' -f2-)
elif [[ $line =~ "Commit:" ]]
then
ENTRY['commit']=$(echo "$line" | cut -d ' ' -f2-)
elif [[ $line != "" ]]
then
if [[ ${ENTRY['message']} == "" ]]
then
ENTRY['message']="$line"
else
ENTRY['message']="${ENTRY['message']}\n$line"
fi
fi
done < $GIRNEL
insert
}
query()
{
create_db
if [[ $# -ge 1 ]]
then
sqlite3 /tmp/girnel.db "$1"
else
sqlite3 /tmp/girnel.db
fi
if [[ $(ls /tmp/girnel.db 2> /dev/null) != "" ]]
then
rm /tmp/girnel.db
fi
}
main()
{
declare -A OPTIONS=(
['-r']=false
['-w']=false
['-q']=false
)
if [[ $# -eq 0 ]]
then
compose
write
else
if [[ "$1" != "-r" && "$1" != "-w" && "$1" != "-q" ]]
then
help
else
OPTIONS["$1"]=true
fi
fi
if [[ ${OPTIONS['-r']} == "true" ]]
then
less $GIRNEL
elif [[ ${OPTIONS['-w']} == "true" ]]
then
if [[ $# -gt 1 ]]
then
echo "$2" > /tmp/girnel
write
else
compose
write
fi
elif [[ ${OPTIONS['-q']} == "true" ]]
then
if [[ $# -gt 1 ]]
then
query "$2"
else
query
fi
fi
}
setup
main "$@"
Offline
This is my demon for keeping track of file attributes:
# Esqueleto de demonio para mantenimiento de atributos extendidos de archivo
##########
#!/bin/bash
getfattr --version||exit
setfattr --version||exit
CONFIG_DIR="/etc/attr.d/monitoring.conf"
cat "$CONFIG_DIR"|
while read config; do
monitoring_directory="$(echo "$config"|cut -d' ' -f1)"
EVENTS="$(echo "$config"|cut -d' ' -f2)"
options="$(echo "$config"|cut -d' ' -f3)"
EVENTS="${EVENTS//,/ }"
options="${options//,/ --}"
echo "$EVENTS"
inotifywait --quiet --monitor --no-dereference --recursive "$monitoring_directory" -- |
while read event; do
#####Definiendo las variable globales
event_dir="$(echo $event|
cut -d' ' -f1)"
event_type="$(echo $event|
cut -d' ' -f2)"
event_file="$(echo $event|
cut -d' ' -f3)"
[[ "$event_dir" == "${event_dir///./}" ]]||
event_type=IGNORE_IT
echo event = $event_type
echo eventdiff = "${event_dir///./}"
for EVENT_ in $EVENTS; do
if [[ "$EVENT_" == "$event_type" ]]; then
#####Iniciando algunas variables generales: fecha, hora, tamaño, etc
ttime=$(date +%s)
humandate="$(date +%Y-%M-%d' '%H:%m:%S.%N' '%z)"
size=$(wc -c "$event_dir""$event_file"|
cut -d' ' -f1)
echo size before= $size
case $event_type in
'MODIFY') ####obteniendo los atributos
echo size after= $size
watch=3600 #####periodo de latencia entre modificiones para ser considerada como tal
sizewatch=350
history=$(getfattr -d --only-values -n user.date.modify.history "$event_dir""$event_file"|
tail -n1)
modifycounter=$(getfattr -d --only-values -n user.modify.counter "$event_dir""$event_file"|
tail -n1)
humanhistory=$(getfattr -d --only-values -n user.date.modify.history.human "$event_dir""$event_file"|
tail -n1)
sizehistory=$(getfattr -d --only-values -n user.size.history "$event_dir""$event_file"|
tail -n1)
#####Procesando algunos datos
lastmodify=$(echo $history|
rev|
cut -d, -f1|
rev)
lastsize=$(echo $sizehistory|
rev|
cut -d, -f1|
rev)
echo last= $lastmodify
echo since last=$elapsed
elapsed=$(echo $ttime-0$lastmodify|
bc)
sizediff=$(echo $size-0$lastsize|
bc)
sizediff=${sizediff#-}
#### echo $ttime-$lastmodify,0 ###se graban cambios cada mas de 1 hora desde el último cambio
######Actualizando las variables
modifycounter=$(echo 0$modifycounter+1|bc)
#####Se usa el periodo watch para revisar si la modificacion es relevante
if [[ $elapsed -gt $watch ]]||[[ sizediff -gt $sizewatch ]]; then
echo doing shit
sizehistory="$sizehistory","$size"
history=$history,$ttime
humanhistory="$humanhistory,$humandate"
########Reformateando variables de valores únicos
sizehistory=$(echo "$sizehistory"|
tr \, '\n'|
uniq|
tr '\n' \,)
sizehistory="${sizehistory%,}"
####Actualiazando los atributos
setfattr --raw -n user.date.modify.history -v "${history#,}" "$event_dir""$event_file"
setfattr --raw -n user.date.modify.history.human -v "${humanhistory#,}" "$event_dir""$event_file"
setfattr --raw -n user.modify.counter -v $modifycounter "$event_dir""$event_file"
setfattr --raw -n user.size.history -v "${sizehistory#,}" "$event_dir""$event_file"
fi
;;
CREATE)
Definiendo algunas variables necesarias
mime_type=$(file -bi "$event_dir""$event_file")
disklabel=$(lsblk $(df -P ~/media/human_bkp/|tail -n1|cut -d' ' -f1) -o LABEL|
tail -n1)
diskuuid=$(lsblk $(df -P ~/media/human_bkp/|tail -n1|cut -d' ' -f1) -o UUID|
tail -n1)
######Inicializando los atributos
getfattr -n user.date.origin "$event_dir""$event_file"||
setfattr -n user.date.origin -v $ttime "$event_dir""$event_file"
getfattr -n user.date.origin.human "$event_dir""$event_file"||
setfattr -n user.date.origin.human -v "$humandate" "$event_dir""$event_file"
getfattr -n user.hostname.origin "$event_dir""$event_file"||
setfattr -n user.hostname.origin -v "$HOSTNAME" "$event_dir""$event_file"
getfattr -n user.disk.label.origin "$event_dir""$event_file"||
setfattr -n user.disk.label.origin -v "$disklabel" "$event_dir""$event_file"
getfattr -n user.disk.uuid.origin "$event_dir""$event_file"||
setfattr -n user.disk.uuid.origin -v "$diskuuid" "$event_dir""$event_file"
getfattr -n user.fullpath.origin "$event_dir""$event_file"||
setfattr -n user.fullpath.origin -v "$event_dir""$event_file" "$event_dir""$event_file"
getfattr -n user.size.origin "$event_dir""$event_file"||
setfattr --raw -n user.size.origin -v $size "$event_dir""$event_file"
getfattr -n user.modify.counter "$event_dir""$event_file"||
setfattr --raw -n user.modify.counter -v 0 "$event_dir""$event_file"
getfattr -n user.mime.type "$event_dir""$event_file"||
setfattr --raw -n user.mime.type -v $mime_type "$event_dir""$event_file"
;;
MOVED_TO)#####Obteniendo algunas variables
disklabel=$(lsblk $(df -P ~/media/human_bkp/|tail -n1|cut -d' ' -f1) -o LABEL|
tail -n1)
diskuuid=$(lsblk $(df -P ~/media/human_bkp/|tail -n1|cut -d' ' -f1) -o UUID|
tail -n1)
#### obteniendo atributos
datemoved=$(getfattr -d --only-values -n user.date.moved.history "$event_dir""$event_file"|
tail -n1)
humandatemoved=$(getfattr -d --only-values -n user.date.moved.history.human "$event_dir""$event_file"|
tail -n1)
path_history=$(getfattr -d --only-values -n user.fullpath.history "$event_dir""$event_file"|
tail -n1)
moved_history=$(getfattr -d --only-values -n user.moved.fullpath.history "$event_dir""$event_file"|
tail -n1)
host_history=$(getfattr -d --only-values -n user.hostname.history "$event_dir""$event_file"|
tail -n1)
disklabel_history=$(getfattr -d --only-values -n user.disk.label.history "$event_dir""$event_file"|
tail -n1)
diskuuid_history=$(getfattr -d --only-values -n user.disk.uuid.history "$event_dir""$event_file"|
tail -n1)
host_movedhistory=$(getfattr -d --only-values -n user.moved.hostname.history "$event_dir""$event_file"|
tail -n1)
moved_counter=$(getfattr -d --only-values -n user.moved.counter "$event_dir""$event_file"|
tail -n1)
##### Redefiniendo variables
datemoved=$datemoved,$ttime
humandatemoved="$humandatemoved","$humandate"
path_history="$path_history","$event_dir""$event_file"
moved_history="$moved_history","$event_dir""$event_file"
host_history=$host_hisory,"$HOSTNAME"
disklabel_history=$disklabel_hisory,"$disklabel"
diskuuid_history=$diskuuid_hisory,"$diskuuid"
host_movedhistory=$host_movedhisory,$HOSTNAME
moved_counter=$(echo 0$moved_counter+1|bc)
###Formateando algunas variables
host_history=$(echo $host_history|###### Eliminando valores contiguos.
tr \, '\n'|
uniq|
tr '\n' \,)
host_history=${host_history%,}
disklabel_history=$(echo $disklabel_history|###### Eliminando valores contiguos.
tr \, '\n'|
uniq|
tr '\n' \,)
disklabel_history=${diskuuid_history%,}
diskuuid_history=$(echo $diskuuid_history|###### Eliminando valores contiguos.
tr \, '\n'|
uniq|
tr '\n' \,)
diskuuid_history=${diskuuid_history%,}
host_movedhistory=$(echo $host_movedhistory|
tr \, '\n'|
uniq|
tr '\n' \,)
host_movedhistory=${host_movedhistory%,}
#####Aplicando atributos
setfattr -n user.date.moved.history -v "${datemoved#,}" "$event_dir""$event_file"
setfattr -n user.date.moved.history.human -v "${humandatemoved#,}" "$event_dir""$event_file"
setfattr -n user.fullpath.history -v "${path_history#,}" "$event_dir""$event_file"
setfattr -n user.moved.fullpath.history -v "${moved_history#,}" "$event_dir""$event_file"
setfattr -n user.hostaname.history -v "${host_history#,}" "$event_dir""$event_file"
setfattr -n user.disk.label.history -v "${disklabel_history#,}" "$event_dir""$event_file"
setfattr -n user.disk.uuid.history -v "${diskuuid_history#,}" "$event_dir""$event_file"
setfattr -n user.moved.hostaname.history -v "${host_movedhistory#,}" "$event_dir""$event_file"
setfattr -n user.moved.counter -v "$moved_counter" "$event_dir""$event_file"
;;
_ACCESS) #### obteniendo atributos #El puto sitema operativo no se entera de nada
#### hay que interpretar patrones de eventos para que esto funcione como se debe
#### no digas que no lo sabías
datecopied=$(getfattr -d --only-values -n user.date.copied.history "$event_dir""$event_file"|
tail -n1)
humandatecopied=$(getfattr -d --only-values -n user.date.copied.history.human "$event_dir""$event_file"|
tail -n1)
path_history=$(getfattr -d --only-values -n user.fullpath.history "$event_dir""$event_file"|
tail -n1)
copied_history=$(getfattr -d --only-values -n user.copied.fullpath.history "$event_dir""$event_file"|
tail -n1)
host_history=$(getfattr -d --only-values -n user.hostname.history "$event_dir""$event_file"|
tail -n1)
host_copiedhistory=$(getfattr -d --only-values -n user.copied.hostname.history "$event_dir""$event_file"|
tail -n1)
copied_counter=$(getfattr -d --only-values -n user.copied.counter "$event_dir""$event_file"|
tail -n1)
##### Redefiniendo variables
datecopied=$datecopied,$ttime
humandatecopied="$humandatecopied","$humandate"
path_history="$path_history","$event_dir""$event_file"
copied_history="$copied_history","$event_dir""$event_file"
host_history=$host_hisory,"$HOSTNAME"
host_copiedhistory=$host_copiedhisory,$HOSTNAME
copied_counter=$(echo 0$copied_counter+1|bc)
###Formateando algunas variables
host_history=$(echo $host_history|###### Eliminando valores contiguos.
tr \, '\n'|
uniq|
tr '\n' \,)
host_history=${host_history%,}
host_copiedhistory=$(echo $host_copiedhistory|
tr \, '\n'|
uniq|
tr '\n' \,)
host_copiedhistory=${host_movedhistory%,}
#####Aplicando atributos
setfattr -n user.date.copied.history -v "${datecopied#,}" "$event_dir""$event_file"
setfattr -n user.date.copied.history.human -v "${humandatecopied#,}" "$event_dir""$event_file"
setfattr -n user.fullpath.history -v "${path_history#,}" "$event_dir""$event_file"
setfattr -n user.copied.fullpath.history -v "${copied_history#,}" "$event_dir""$event_file"
setfattr -n user.hostaname.history -v "${host_history#,}" "$event_dir""$event_file"
setfattr -n user.copied.hostaname.history -v "${host_copiedhistory#,}" "$event_dir""$event_file"
setfattr -n user.copied.counter -v "$copied_counter" "$event_dir""$event_file"
;;
esac
fi
done
done
done
config file:
/home/human/ CREATE,MODIFY,MOVED_TO,COPIED_TO exclude=/home/human/cdrom/useless/'\.*'
And I think that every modern system should implement something like this as an integrated option.
Offline
Storing CD-ROM images for video game emulation can eat nasty amounts of storage space. Fortunately, both PS1 and PS2 emulators support compressed images nowadays. The mame project has come up with a format they call "Compressed Hunks of Data", short chd. There is a chdman utility in mame-tools, that allows converting bin/cue image combos to chd files with great compression ratios. I started compressing my entire Playstation 1 library, but I forgot to somehow log the compression ratios per image, so I needed a tool, that adds the sizes of all the .bin files belonging to a cue file together and compares it with the .chd file.
#!/bin/bash
cuename="$1"
bindir=$(dirname "$1")
chdname=${cuename/cue/chd}
chdsize=$(stat -c %s "$chdname")
totalsize=0
rawout() {
IFS=$'\n'
for i in $(grep -o "\".*.bin\"" "$cuename" | sed s/\"/\/g);do
binsize=$(stat -c %s "$bindir/$i")
echo "$i|$(($binsize/1048576))|MiB"
totalsize=$(expr $binsize + $totalsize)
done
unset IFS
ratio=$(bc<<<"scale=2; $chdsize/$totalsize")
echo "$(basename "$cuename")|$(($totalsize/1048576))|MiB|(total)"
echo "$(basename "$chdname")|$(($chdsize/1048576))|MiB|(ratio: $ratio)"
}
rawout | column -t -s "|" -R 2
The output looks like this:
$ chdratio "Big Bass Fishing (USA).cue"
Big Bass Fishing (USA) (Track 01).bin 33 MiB
Big Bass Fishing (USA) (Track 02).bin 11 MiB
Big Bass Fishing (USA) (Track 03).bin 11 MiB
Big Bass Fishing (USA) (Track 04).bin 11 MiB
Big Bass Fishing (USA) (Track 05).bin 9 MiB
Big Bass Fishing (USA) (Track 06).bin 9 MiB
Big Bass Fishing (USA) (Track 07).bin 11 MiB
Big Bass Fishing (USA) (Track 08).bin 9 MiB
Big Bass Fishing (USA) (Track 09).bin 10 MiB
Big Bass Fishing (USA) (Track 10).bin 4 MiB
Big Bass Fishing (USA) (Track 11).bin 11 MiB
Big Bass Fishing (USA) (Track 12).bin 30 MiB
Big Bass Fishing (USA).cue 163 MiB (total)
Big Bass Fishing (USA).chd 74 MiB (ratio: .45)
It depends on bc, because bash doesn't float.
Offline
System upgrade bash script to run reflector, informant and pacdiff when doing system upgrade (pacman and AUR). Also removes orphans:
#!/bin/bash
#
# Runs reflector, informant and pacdiff with system upgrade, and removes orphans
#
# Compare current reflector results with existing mirrorlist, and choose whether to
# update the mirrorlist
#
printf "Review reflector update to the mirror list before system upgrade (pacman and aur).\n"
printf "The most recently synchronized U.S. https mirrors, sorted by highest mirror score, are:\n"
reflector -n 5 -c US --connection-timeout 1 --download-timeout 1 -p "https" --sort score | tee /tmp/ml
printf "\nThe existing /etc/pacman.d/mirrorlist is:\n"
cat /etc/pacman.d/mirrorlist
echo -n "Replace /etc/pacman.d/mirrorlist ([Y]/n)? "
read -r overwrite
if [ "$overwrite" == "${overwrite#[Yn]}" ]
then
sudo mv /tmp/ml /etc/pacman.d/mirrorlist
printf "\n/etc/pacman.d/mirrorlist has been updated."
else
printf "\nSkipping update of /etc/pacman.d/mirrorlist, and using existing list.\n"
fi
#
printf "\nNow checking for new Arch news.\n"
/usr/bin/informant check
#
# Ugrade system with pacman and aur utilities, then remove orphans and run pacdiff
#
echo -n "Proceed with system upgrade using pacman and aur sync (aurutils) ([Y]/n)? "
read -r proceed
if [ "$proceed" == "${proceed#[Yn]}" ]
then
printf "\nNow running pacman -Syu, then aur sync -u\n"
sudo pacman -Syu
aur sync -u
printf "Removing orphans if found...\n"
sudo pacman -Rns $(pacman -Qtdq)
printf "\nNow running pacdiff...\n"
sudo pacdiff
printf "\nDone!\n"
else
printf "\nSkipping system upgrade.\n"
fi
$SHELL
Modified following Trilby's comments (#3612).
Last edited by zpg443 (2021-09-27 02:03:25)
Offline
"$cmd > file; cat file" can just be "$cmd | tee file", and "cp a b; rm a" should just be "mv a b" - this is particularly helpful if the mv/cp fails: using cp and rm, you'll loose the new mirrorlist content if the copy fails, using mv, it'll still be there if the move fails. Of course if you are going to stick with the 'rm', there'd be no reason for it to be in both branches of the conditional: pull it out and just run it unconditionally after the if / else blocks.
Last edited by Trilby (2021-09-26 22:52:48)
"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman
Offline
About tee - This image from Wikipedia enlightened me some time ago. Specially useful if the file can only be written as root.
Last edited by icar (2021-09-27 00:18:51)
Offline
Yes, I'm too lazy to TAB-complete...
#!/usr/bin/env bash
# play videos
dir=$HOME/Downloads/Videos/TV
IFS=$'\n'
# requires mpv
type mpv > /dev/null 2>&1 || {
printf "%s\n" "No mpv installed, bailing...";
exit 1;
}
# build array of candidates
read -r -d '' -a files < \
<(find "$dir" -maxdepth 2 -type f \( \
-iname "*$1*" \
-not -name "*.srt" \) 2>/dev/null)
# check for multiple matches
if (( ${#files[@]} > 1 )); then
prefix="${files%/*}"
PS3="Select your video: "
printf "%s\n" "There are ${#files[@]} matches"
select vid in "${files[@]##*/}"; do
files="$vid"
break
done
fi
# play it like you mean it
if [[ -n $files && -n $prefix ]]; then
mpv "$prefix"/"${files}"
elif [[ -n "$files" ]]; then
mpv "$files"
else
printf "%s\n" "No matches to play"
fi
# vim:set sw=2 ts=2 et:
Offline
Kid3-cli and kid3-qt are great utilities for managing music libraries, but they do not provide a utility to build a complete music library database at once. In the kid3-qt GUI, there is an export utility, but it is GUI and it only exports one folder at a time.
This coding novice built a bash script to try and bridge that gap.
https://github.com/Harpo3/musicbase
It uses the kid3-qt configuration file ($HOME/.config/Kid3/Kid3.conf) to set some albeit arbitrary format codes to establish record values and applies the format using kid3-cli. Obviously, these two programs would be dependencies of this script.
As always, feedback is appreciated. I plan to add user-level ability to set format codes according to need.
#!/bin/bash
set -e
# Help Function #
############################################################
Help()
{
# Display Help
printf '\n'
printf 'Musicbase - A kid3-based music library database creation utility.\n\n'
printf 'syntax: musicbase.sh DIRPATH [-h] [-m MINDEPTH] [-o FILE] [q]\n\n'
printf 'Generates a music library database using music file tag data and kid3-cli/kid3-qt export tools.\n'
printf 'Processes data from music files at the DIRPATH specified. File type is data separated values (DSV)\nwith carat (^) as the delimiter. Database records include the path to each music file.\n\n'
printf 'Time to complete varies by processor and can take >10 minutes for large libraries. Check\n'
printf 'output quality more quickly by testing on a subdirectory.\n\n'
printf 'options:\n'
printf ' -h display this help file\n'
printf ' -m minimum subdirectory depth from top directory of music library to music files (default: 1)\n'
printf ' -o specify output file name and path (default: %s)\n' "\$HOME/.musiclib.dsv"
printf ' -q quiet - hide terminal output\n'
printf '\n'
}
# Verify user provided required, valid path
if [ -z "$1" ]
then
printf '\nMissing required argument: path to music directory.\n'
Help
exit 1
fi
if [ -d "$1" ]; then
libpath=$1
shift
else
if [ "$1" == "-h" ]; then
Help
exit 1
fi
printf 'This directory does not exist: '
printf '%s\n' "$1"
exit 1
fi
# Set default variables
dirdepth=1
outpath="$HOME/.musiclib.dsv"
showdisplay=1
# Use getops to set any user-assigned options
while getopts ":hm:o:q" opt; do
case $opt in
h) # display Help
Help
exit;;
m)
dirdepth=$OPTARG
shift
;;
o)
outpath=$OPTARG
;;
q)
showdisplay=0 >&2
;;
\?)
printf 'Invalid option: -%s\n' "$OPTARG"
exit 1
;;
:)
printf 'Option -%s requires an argument.\n' "$OPTARG"
exit 1
;;
esac
done
# Get list of music subdirectories, using first variable $libpath for library folder, e.g. /mnt/vboxfiles/music
find "$libpath" -mindepth "$dirdepth" -type d > "$HOME"/.albumdirs;
if [ $showdisplay == 0 ]
then
printf 'Locating all subdirectories under this path...\n' > /dev/null 2>&1
else
printf 'Locating all subdirectories under this path...\n'
fi
# Verify kid3-qt 'musicbase' export format exists-> $HOME/.config/Kid3/Kid3.conf
# If exists is false, add export format to $HOME/.config/Kid3/Kid3.conf; otherwise skip and proceed
kid3confpath=$"$HOME/.config/Kid3/Kid3.conf"
if grep -q "musicbase" "$kid3confpath"
then
if grep -q "%{catalognumber}^%{artist}^%{grouping}^%{album}^%{albumartist}^%{title}^%{filepath}^%{genre}^%{seconds}000^%{rating}^^%{songs-db_custom2}^%{work}" "$kid3confpath"
then
printf ''
else
printf 'A kid3-qt export format was found with the musicbase name, but its format is not a match. Delete this format in kid3-qt, then run musicbase again.\n'
exit
fi
else
if [ $showdisplay == 0 ]
then
printf 'Adding the musicbase export format to kid3-qt configuration.\n' > /dev/null 2>&1
else
printf 'Adding the musicbase export format to kid3-qt configuration.\n'
fi
exportformatidx="$(grep -oP '(?<=ExportFormatIdx=)[0-9]+' "$kid3confpath")"
# add comma and space to end of ExportFormatHeaders string
sed -in '/^ExportFormatHeaders/ s/$/, /' "$kid3confpath"
# add count of 1 to existing value of ExportFormatIdx
(( exportformatidx++ ))
sed -i '/ExportFormatIdx.*/c\ExportFormatIdx='"$exportformatidx" "$kid3confpath"
# add comma, space and value 'musicbase' to end of ExportFormatNames string
sed -in '/^ExportFormatNames/ s/$/, musicbase/' "$kid3confpath"
# add comma, space and format string to end of ExportFormatTracks string
sed -in '/^ExportFormatTracks/ s/$/, %{catalognumber}^%{artist}^%{grouping}^%{album}^%{albumartist}^%{title}^%{filepath}^%{genre}^%{seconds}000^%{rating}^^%{songs-db_custom2}^%{work}/' "$kid3confpath"
# add comma and space to the end of ExportFormatTrailers string
sed -in '/^ExportFormatTrailers/ s/$/, /' "$kid3confpath"
fi
# Build music library database
if [ $showdisplay == 0 ]
then
printf 'Building database. This can take time for kid3-cli to process, especially for large music libraries...\n' > /dev/null 2>&1
else
printf 'Building database. This can take time for kid3-cli to process, especially for large music libraries...\n'
fi
# This is for the spinner, to show the program is working
if [ $showdisplay == 1 ]
then
i=1
sp="/-\|"
echo -n ' '
else
printf ''
fi
# Add header to the database file
echo "ID^Artist^IDAlbum^Album^AlbumArtist^SongTitle^SongPath^Genre^SongLength^Rating^LastTimePlayed^Custom2^GroupDesc" > "$outpath"
# Loop through the albumdirs file using kid3-cli to read the tag info and add it to the database file,
# while running the spinner to show operation
while IFS= read -r line; do
kid3-cli -c "export /tmp/musiclib.dsv musicbase '%{catalognumber}^%{artist}^%{grouping}^%{album}^%{albumartist}^%{title}^%{filepath}^%{genre}^%{seconds}000^%{rating}^^%{songs-db_custom2}^%{work}'" "$line"
cat /tmp/musiclib.dsv >> "$outpath"
if [ $showdisplay == 0 ]
then
printf '' > /dev/null 2>&1
else
printf '\b%s' "${sp:i++%${#sp}:1}"
fi
done < "$HOME"/.albumdirs
# Sort library order using file path column, preserving position of header, and replace library file
(head -n 1 "$outpath" && tail -n +2 "$outpath" | sort -k7 -t '^') > /tmp/musiclib.dsv
cp /tmp/musiclib.dsv "$outpath"
if [ $showdisplay == 0 ]
then
printf 'Finished! Output: %s\n\n' > /dev/null 2>&1"$outpath"
else
printf 'Finished! Output: %s\n\n' "$outpath"
fi
#EOF
EDIT: "$HOME"/.albumdirs should be changed to /tmp/albumdirs
EDIT: See Github link for changes made since original post.
Last edited by zpg443 (2021-10-19 23:07:07)
Offline
You can remove '-z "$1"' check
if (( ${#@} > 0 )); then
while getopts ":hm:o:q" opt; do
case $opt in
h)
Help
exit 0
;;
*)
printf '%s\n' "Error: Wrong option. Try '${app_this} -h'."
exit 1
;;
esac
done
else
print_help
exit 1
fi
The check is the same as 'run_archiso' uses
Same for all the printf in 'Help', useless...
app_this="${0##*/}"
print_help(){
local usagetext
IFS='' read -r -d '' usagetext <<EOF || true
Usage: ${app_this} [option]
Options:
-h display this help file\n'
-m minimum subdirectory depth from top directory of music library to music files (default: 1)
......
Description
Musicbase - A kid3-based music library database creation utility.
syntax: musicbase.sh DIRPATH [-h] [-m MINDEPTH] [-o FILE] [q]
.....
EOF
printf '%s' "${usagetext}"
}
and
printf 'Locating all subdirectories under this path...\n' > /dev/null 2>&1
printf 'Locating all subdirectories under this path...\n'
to
printf '%s\n' "Locating all subdirectories under this path..." > /dev/null 2>&1
printf '%s\n' "Locating all subdirectories under this path..."
Do with it what you like of course;-) but these are things I saw in a glace.
Haven't even looked at the rest of it...
Offline
Yes, the help file was a train wreck! Thanks for the suggestions.
Offline
Yes, the help file was a train wreck! Thanks for the suggestions.
You don't actually need the "printf '%s\n'" it's fine to use a newline at the end of your line, unless there's a string in it, but even then a 'printf "Some text"' would mostly be enough, it depends...
Offline
Why create a variable from that heredocument just to print it out immediately after, just cat:
cat << 'EOF'
Help info line one
Line two indented a bit more
And more ...
EOF
I've also embedded help info in a top-of-file comment before:
#!/bin/sh
#
#| ProgramName - Description
#| Version 0.0.0
#|
#| Usage: ...
#|
#| Options:
#| ...
help() {
sed -n 's/^#|//p' "$0";
}
The pipe there is arbitrary, and is just to differentiate help lines from regular comments. You can use different prefixes in place of the pipe to differentiate help output, version output, etc.
Last edited by Trilby (2021-10-19 19:44:41)
"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman
Offline
Why create a variable from that heredocument just to print it out immediately after, just cat:
cat << 'EOF'
Though, I don't disagree;-) 'cat!=POSIX=coreutils' and 'read variable=builtin/POSIX'...
Offline
What? Are you saying 'cat' is not posix? Wrong. As for being a builtin, that depends entirely on the shell and is not dictated by a standard. In fact, in my shell, cat is a builtin ... and coincidentally, your read command does not work the way it is intended.
But as the shebang was bash anyways (and there were other bashisms) then pure POSIX compliance is irrelevant.
Last edited by Trilby (2021-10-19 21:20:23)
"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman
Offline
I than stand corrected, I was always assuming the man page should mention if the tool is POSIX.
What's wrong with that read command? I use it from an Archiso tool 'run_archiso' the '-d' may not be correct I'm actually not sure what it does...
It does correctly show my help files.
Offline
https://man.archlinux.org/man/core/man-pages/read.1p.en
POSIX specifies only "-r" as parameter for read. Everything else is an extension by your shells implmentation (ie. a bashism)
Edit: see "read --help", the "-d" parameter is explained there.
Last edited by seth (2021-10-19 22:15:55)
Online
Ah, now it makes sense, thanks seth & Trilby;-)
'-d delim'
BTW. running 'read --help' = 'read: bad option: -h'
Offline
BTW. running 'read --help' = 'read: bad option: -h'
zsh?
'read --help' is a bashist-bashism
Online