You are not logged in.

#3751 2023-12-29 23:59:17

seth
Member
Registered: 2012-09-03
Posts: 58,698

Re: Post your handy self made command line utilities

[ $# -gt 1 ]

Offline

#3752 2024-01-23 20:58:24

ugjka
Member
From: Latvia
Registered: 2014-04-01
Posts: 1,862
Website

Re: Post your handy self made command line utilities


https://ugjka.net
paru > yay | vesktop > discord
pacman -S spotify-launcher
mount /dev/disk/by-...

Offline

#3753 2024-03-12 09:48:33

Nebulosa
Member
Registered: 2009-08-24
Posts: 48

Re: Post your handy self made command line utilities

Edit: added -u and -b options

https://0x0.st/HFPc.sh

#!/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

Last edited by Nebulosa (2024-03-14 06:48:55)

Offline

#3754 2024-03-12 11:01:40

Nebulosa
Member
Registered: 2009-08-24
Posts: 48

Re: Post your handy self made command line utilities

https://0x0.st/X-qs.sh

#!/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 --
}


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 || exit 1
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

Edit: fixies

Last edited by Nebulosa (2024-04-11 19:01:59)

Offline

#3755 2024-03-22 10:17:21

gcb
Member
Registered: 2014-02-12
Posts: 167

Re: Post your handy self made command line utilities

easily check a dependency list

# check dependencies
for dependency in "sed" "git"; do
	command -v $dependency >/dev/null 2>&1 || { echo "Require $dependency command. Not found." >&2; exit 1; }
done

retry some code (in the while line)

# Retry failed command two more times for a total of 3 tries
max_retries=2;
while ! ls i_do_not_exist
do
  ((max_retries--)) || break
  echo "Retrying after delay... ${max_retries} try left"
  sleep 2;
done

my favorite of late: a way to add comments to a long list of parameters. very handy with things that lack conf files when they should exist (like rclone) or when they are just long lived hacks (like dealing with docker)

# comment parameters using an array! copy literary from the command --help and add `#` after the actual flag
RCLONEFLAGS=(
	--progress # show progress
	--no-update-modtime # trust server time instead of file meta-data
        ...million more lines...
)
rclone copy ${RCLONEFLAGS[@]}

and the bane of my existence with bash. it joins quoted strings.

# x='a'"'"'b' === 'a' + "'" + 'b' === 'a'\''b' => 'a'+\'+'b' => 'a\'b'

And you cannot escape single quotes, so the last one up there is "invalid" bash.

Offline

#3756 2024-03-22 13:48:26

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 30,330
Website

Re: Post your handy self made command line utilities

gcb wrote:

easily check a dependency list...

I think you mean `pacman -T sed git`.


"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman

Offline

#3757 2024-04-03 17:13:52

gcb
Member
Registered: 2014-02-12
Posts: 167

Re: Post your handy self made command line utilities

Trilby wrote:
gcb wrote:

easily check a dependency list...

I think you mean `pacman -T sed git`.

That's a package search smile

It's fine if you are coding script hooks for a package or install inscripts. other than that it is the wrong tool.

Offline

#3758 2024-04-11 14:47:06

4ndr0666
Member
Registered: 2024-04-11
Posts: 2

Re: Post your handy self made command line utilities

Interactively creates a live ISO menu entry at boot with dependency checks and idempotency:

#!/bin/bash

# Auto escalate to root
if [ "$(id -u)" -ne 0 ]; then
    echo "Attempting to escalate to root..."
    sudo "$0" "$@"
    exit $?
fi

# Variables
grub_cfg_path="/boot/grub/grub.cfg"
custom_entry_path="/etc/grub.d/40_custom"
entry_identifier="Arch" # Unique identifier for the custom entry

# Prompt for the ISO path
read -p "Enter the path to the ISO file (e.g., /boot/isos/arch.iso): " iso_path

# Check and create grub.cfg and 40_custom if they do not exist
if [ ! -f "${grub_cfg_path}" ]; then
    echo "grub.cfg not found. Creating..."
    touch "${grub_cfg_path}"
fi

if [ ! -f "${custom_entry_path}" ]; then
    echo "40_custom not found. Creating..."
    cat << 'EOF' > "${custom_entry_path}"
#!/bin/sh
exec tail -n +3 $0
EOF
    chmod +x "${custom_entry_path}"
fi

# Check for existing menu entry to ensure idempotency
if ! grep -q "${entry_identifier}" "${custom_entry_path}"; then
    # Append custom menu entries to 40_custom if not already present
    cat << EOF >> "${custom_entry_path}"

# Custom menu entries
menuentry "${entry_identifier}" {
    iso_path="${iso_path}"
    export iso_path
    search --set=root --file \$iso_path
    probe -u \$root --set=rootuuid
    export rootuuid
    loopback loop \$iso_path
    root=(loop)
    configfile /boot/grub/loopback.cfg
    loopback --delete loop
}

menuentry 'Reboot Computer' --class restart {
    reboot
}

menuentry 'Shutdown Computer' --class shutdown {
    halt
}
EOF
    echo "Custom GRUB entries added."
else
    echo "Custom GRUB entry '${entry_identifier}' already exists. No changes made."
fi

# Update GRUB configuration
echo "Updating GRUB configuration..."
grub-mkconfig -o "${grub_cfg_path}"

echo "GRUB configuration has been updated. Please reboot to see the changes."

Offline

#3759 2024-04-11 18:51:58

Nebulosa
Member
Registered: 2009-08-24
Posts: 48

Re: Post your handy self made command line utilities

4ndr0666 wrote:

... creates a live ISO menu entry at boot ...

Fun fact, but I posted almost the exact same script above smile

Last edited by Nebulosa (2024-04-11 18:57:21)

Offline

#3760 2024-04-12 06:03:19

4ndr0666
Member
Registered: 2024-04-11
Posts: 2

Re: Post your handy self made command line utilities

Nebulosa wrote:

Fun fact, but I posted almost the exact same script above :smile:

Last edited by Nebulosa (Today 12:57:21)

Hey Nebulosa,

I see you, lets take it to the next level then:


#!/bin/bash
# File: liveiso_boot_entry.sh
# Author: 4ndr0666
# Date: 04-11-2024
#
# --- // LIVEISO_BOOT_ENTRY.SH // ========

# --- // COLORS:
CYAN='\033[0;36m'
GREEN='\033[0;32m'
NC='\033[0m'  # No Color

# --- // TRAP:
cleanup() {
    echo -e "${CYAN}Cleaning up... Please wait."
    # Add any cleanup commands here
    echo -e "Cleanup complete.${NC}"
    exit 1  # Ensure the script exits after cleanup
}
trap cleanup SIGINT SIGTERM EXIT

# --- // ROOT:
escalate() {
    if [ "$(id -u)" -ne 0 ]; then
        echo -e "${CYAN}CAUTION: You are now superuser...${NC}"
        exec sudo "$0" "$@"
    fi
}

# --- // DEPS:
dependencies() {
    local required_cmds="curl grep sed sha256sum tee cat find jq btrfs blkid findmnt grub-mkconfig wget"
    for cmd in $required_cmds; do
        if ! command -v $cmd &> /dev/null; then
            echo -e "${CYAN}Error: Required command '$cmd' not found.${NC}"
            exit 1
        fi
    done
}

# --- // FS:
filesystem_type() {
    read -r -p "Select your filesystem type for operations (ext4 or btrfs): " filesystem_type
    if [[ $filesystem_type != "ext4" && $filesystem_type != "btrfs" ]]; then
        echo -e "${CYAN}Unsupported filesystem type. Exiting.${NC}"
        exit 1
    fi
}

# --- // VARIABLES:
setup_variables() {
    subvol="@iso_subvol"
    folder="/mnt/iso_subvol"
    rootdrive=$(findmnt -n -o SOURCE /)
    rootuuid=$(blkid -s UUID -o value "$rootdrive")
}

# --- // BOOTLOADER:
check_bootloader() {
    if [ -d /boot/efi/loader/entries ]; then
        echo -e "${CYAN}System is managed by systemd-boot.${NC}"
        bootloader="systemd"
    elif [ -d /boot/grub ]; then
        echo -e "${CYAN}System uses GRUB.${NC}"
        bootloader="grub"
    else
        echo -e "${CYAN}No supported bootloader found. Manual configuration required.${NC}"
        exit 1
    fi
}

# --- // DISTROLIST:
distrolist() {
    echo -e "${CYAN}Fetching available distributions...${NC}"
    declare -A distros=(
            ["Ubuntu"]="https://www.ubuntu.com/download/desktop"
            ["Fedora"]="https://getfedora.org/en/workstation/download/"
            ["Ubuntu"]="https://www.ubuntu.com/download/desktop"
            ["Edubuntu"]="https://edubuntu.org/download"
            ["Kubuntu"]="https://kubuntu.org/getkubuntu/"
            ["Lubuntu"]="https://lubuntu.net/downloads/"
            ["Xubuntu"]="https://xubuntu.org/download"
            ["Ubuntu Budgie"]="https://ubuntubudgie.org/downloads"
            ["Ubuntu Gnome"]="https://cdimage.ubuntu.com/ubuntu-gnome/releases/"
            ["Ubuntu Server"]="https://www.ubuntu.com/download/server"
            ["Ubuntu Studio"]="https://ubuntustudio.org/download/"
            ["Emmabuntus"]="https://sourceforge.net/projects/emmabuntus/files/latest/download"
            ["Linux Mint"]="https://www.linuxmint.com/download.php"
            ["Linux Mint Debian"]="https://www.linuxmint.com/download_lmde.php"
            ["CentOS Live"]="https://www.centos.org/download/"
            ["CentOS Minimal"]="https://www.centos.org/download/"
            ["Debian Live"]="https://cdimage.debian.org/debian-cd/current-live/amd64/iso-hybrid/"
            ["Fedora"]="https://getfedora.org/en/workstation/download/"
            ["OpenSUSE"]="https://get.opensuse.org/desktop/"
            ["Puppy Linux"]="http://distro.ibiblio.org/puppylinux/puppy-fossa/fossapup64-9.5.iso"
            ["BionicPup"]="https://distro.ibiblio.org/puppylinux/puppy-bionic/"
            ["Tahrpup"]="https://distro.ibiblio.org/puppylinux/puppy-tahr/iso/tahrpup64-6.0.5/tahr64-6.0.5.iso"
            ["Fatdog64"]="https://distro.ibiblio.org/fatdog/iso/"
            ["Lucid Puppy Linux"]="https://distro.ibiblio.org/pub/linux/distributions/puppylinux/puppy-5.2.8/lupu-528.005.iso"
            ["Precise Puppy Linux"]="https://distro.ibiblio.org/quirky/precise-5.7.1/precise-5.7.1.iso"
            ["Slacko Puppy"]="https://distro.ibiblio.org/puppylinux/puppy-slacko-6.3.2/64/slacko64-6.3.2-uefi.iso"
            ["Academix"]="https://sourceforge.net/projects/academix/files/latest/download"
            ["AntiX"]="https://sourceforge.net/projects/antix-linux/files/latest/download"
            ["Archbang"]="https://sourceforge.net/projects/archbang/files/latest/download"
            ["Archlinux"]="http://mirrors.us.kernel.org/archlinux/iso/latest/"
            ["EndeavourOS"]="https://mirrors.gigenet.com/endeavouros/iso/EndeavourOS_Galileo-Neo-2024.01.25.iso"
            ["Garuda Hyprland"]="https://iso.builds.garudalinux.org/iso/latest/community/hyprland/latest.iso?r2=1"
            ["Garuda dr460nized"]="https://iso.builds.garudalinux.org/iso/latest/garuda/dr460nized/latest.iso?r2=1"
            ["Garuda Gnome"]="https://iso.builds.garudalinux.org/iso/latest/garuda/gnome/latest.iso?r2=1"
            ["Garuda Xfce"]="https://iso.builds.garudalinux.org/iso/latest/garuda/xfce/latest.iso?r2=1"
            ["Manjaro"]="https://download.manjaro.org/kde/23.1.4/manjaro-kde-23.1.4-240406-linux66.iso"
            ["Axyl"]="https://github.com/axyl-os/axylos-2-iso/releases/download/v2-beta-2024.04.11/axyl-v2-beta-2024.04.11-x86_64.iso"
            ["Archcraft"]="https://sourceforge.net/projects/archcraft/files/latest/download"
            ["CachyOS"]="https://iso.cachyos.org/240401/cachyos-kde-linux-240401.iso"
            ["BigLinux"]="https://iso.biglinux.com.br/biglinux_2024-04-05_k68.iso"
            ["Artix"]="https://artixlinux.org/download.php"
            ["Stormos"]="https://sourceforge.net/projects/hackman-linux/"
            ["Mabox"]="https://sourceforge.net/projects/mabox-linux/files/latest/download"
            ["Bluestar Linux"]="https://sourceforge.net/projects/bluestarlinux/files/latest/download"
            ["Bodhi"]="https://sourceforge.net/projects/bodhilinux/files/latest/download"
            ["CAELinux"]="https://sourceforge.net/projects/caelinux/files/latest/download"
            ["Calculate Linux Desktop"]="http://www.gtlib.gatech.edu/pub/calculate/release/20.6/"
            ["Cub Linux"]="https://sourceforge.net/projects/cublinux/files/latest/download"
            ["Deepin"]="https://sourceforge.net/projects/deepin/files/latest/download"
            ["Endeavour OS"]="https://endeavouros.com/latest-release/"
            ["Feren OS"]="https://sourceforge.net/projects/ferenoslinux/files/latest/download"
            ["JustBrowsing"]="https://sourceforge.net/projects/justbrowsing/files/latest/download"
            ["KDE Neon"]="https://neon.kde.org/download"
            ["KNOPPIX"]="http://ftp.knoppix.nl/os/Linux/distr/knoppix/KNOPPIX_V9.1CD-2021-01-25-EN.iso"
            ["KXStudio"]="https://sourceforge.net/projects/kxstudio/files/latest/download"
            ["LinuxFX"]="https://sourceforge.net/projects/linuxfxdevil/files/latest/download"
            ["Linux Kid X"]="https://sourceforge.net/projects/linuxkidx/files/latest/download"
            ["LXLE Desktop"]="https://sourceforge.net/projects/lxle/files/latest/download"
            ["OpenMandriva"]="https://sourceforge.net/projects/openmandriva/files/latest/download"
            ["mintyMac"]="http://sourceforge.net/projects/mintymacpremium/files/latest/download"
            ["MX Linux"]="https://sourceforge.net/projects/mx-linux/files/latest/download"
            ["Netrunner"]="https://www.netrunner.com/download/"
            ["OSGeo Live"]="https://sourceforge.net/projects/osgeo-live/files/latest/download"
            ["PCLinuxOS"]="https://www.pclinuxos.com/?page_id=10"
            ["Peach OSI"]="https://www.peachosi.com/content/download-patriot"
            ["Pear Linux"]="https://sourceforge.net/projects/pearoslinux/files/latest/download"
            ["Peppermint"]="https://peppermintos.com/guide/downloading/"
            ["Pinguy OS"]="https://sourceforge.net/projects/pinguy-os/files/latest/download"
            ["Porteus"]="http://porteus.org/porteus-mirrors.html"
            ["POP!_OS"]="https://pop.system76.com/"
            ["Q4OS"]="https://sourceforge.net/projects/q4os/files/latest/download"
            ["Raspberry Pi Desktop"]="https://www.raspberrypi.org/software/raspberry-pi-desktop/"
            ["Skywave Linux"]="https://sourceforge.net/projects/skywavelinux/files/latest/download"
            ["SLAX"]="https://www.slax.org/#purchase"
            ["SliTaZ"]="https://www.slitaz.org/en/get/"
            ["LuninuX OS"]="https://sourceforge.net/projects/luninuxos/files/latest/download"
            ["Solus"]="https://getsol.us/download/"
            ["SolydX"]="https://solydxk.com/downloads.php"
            ["Sparky Linux"]="https://sourceforge.net/projects/sparkylinux/files/latest/download"
            ["Sugar on a Stick"]="https://wiki.sugarlabs.org/go/Sugar_on_a_Stick"
            ["Terralinux"]="https://sourceforge.net/projects/terralinuxos/files/latest/download"
            ["Uberstudent"]="https://sourceforge.net/projects/uberstudent/files/latest/download"
            ["Ultimate Edition"]="https://sourceforge.net/projects/ultimateedition/files/latest/download"
            ["Xiaopan"]="https://sourceforge.net/projects/xiaopanos/files/latest/download"
            ["Zorin OS Core"]="https://zorinos.com/download/"
            ["Kodachi"]="https://sourceforge.net/projects/linuxkodachi/files/latest/download"
            ["Liberte"]="https://sourceforge.net/projects/liberte/files/latest/download"
            ["4M Linux"]="https://sourceforge.net/projects/linux4m/files/latest/download"
            ["Antivirus Live CD"]="https://sourceforge.net/projects/antiviruslivecd/files/latest/download"
            ["AVIRA AntiVir Rescue CD"]="https://download.avira.com/download/rescue-system/avira-rescue-system.iso"
            ["Dr.Web LiveDisk"]="https://download.geo.drweb.com/pub/drweb/livedisk/drweb-livedisk-900-cd.iso"
            ["ESET SysRescue Live"]="https://www.eset.com/int/support/sysrescue/#download"
            ["GDATA Rescue CD"]="https://secure.gd/dl-int-bootcd"
            ["Kaspersky Rescue Disk"]="https://rescuedisk.s.kaspersky-labs.com/updatable/2018/krd.iso"
            ["Acronis True Image"]="NONE"
            ["BackBox"]="https://www.backbox.org/download/"
            ["Boot Repair Disk"]="https://sourceforge.net/projects/boot-repair-cd/files/latest/download"
            ["Caine"]="https://www.caine-live.net/page5/page5.html"
            ["Clonezilla"]="https://clonezilla.org/downloads.php"
            ["DBAN"]="https://sourceforge.net/projects/dban/files/latest/download"
            ["Demon Linux"]="https://demonlinux.com/"
            ["DRBL"]="https://sourceforge.net/projects/drbl/files/latest/download"
            ["EASEUS Disk Copy"]="https://download.easeus.com/free/EaseUS_DiskCopy_Home.exe"
            ["Finnix"]="https://www.finnix.org/Download"
            ["G4L"]="https://sourceforge.net/projects/g4l/files/latest/download"
            ["GParted"]="https://sourceforge.net/projects/gparted/files/latest"
            ["GRML"]="https://grml.org/download/"
            ["Kali"]="https://www.kali.org/downloads/"
            ["Memtest86"]="https://www.memtest86.com/download.htm"
            ["Memtest86+"]="https://www.memtest.org/download/5.31b/memtest86+-5.31b.bin.zip"
            ["Matriux"]="https://sourceforge.net/projects/matriux/files/latest/download"
            ["Ophcrack"]="https://sourceforge.net/projects/ophcrack/files/ophcrack-livecd/3.6.0/"
            ["Rescatux"]="https://sourceforge.net/projects/rescatux/files/latest/download"
            ["Rescuezilla"]="https://rescuezilla.com/download.html"
            ["Redo Backup And Recovery"]="https://sourceforge.net/projects/redobackup/files/latest/download"
            ["Rip Linux"]="https://sourceforge.net/projects/riplinuxmeta4s/files/latest/download"
            ["System Rescue"]="https://sourceforge.net/projects/systemrescuecd/files/latest/download"
            ["Trinity Rescue Kit"]="https://trinityhome.org/trinity_rescue_kit_download/"
            ["Ultimate Boot CD"]="http://www.ultimatebootcd.com/download/redirect.php"
            ["Wifislax"]="https://www.wifislax.com/category/download/"
            ["Falcon 4 Boot CD"]="NONE"
            ["Hiren's Boot CD"]="NONE"
            ["Hiren's BootCD PE"]="https://www.hirensbootcd.org/download/"
            ["LinuxCNC"]="https://linuxcnc.org/downloads/"
    )
    PS3="Please select a distribution: "
    select distro in "${!distros[@]}"; do
        if [ -n "$distro" ]; then
            echo -e "${CYAN}You have selected: $distro${NC}"
            break
        else
            echo -e "${CYAN}Invalid selection. Please select a valid option.${NC}"
        fi
    done
    iso_url="${distros[$distro]}"
    iso_path="/iso_storage/$distro.iso"
    echo -e "${CYAN}Preparing to download $distro:${NC}"
    echo -e "${CYAN}Download URL: $iso_url${NC}"
    echo -e "${CYAN}Storing at: $iso_path${NC}"
}

# --- // DIR_CHECK:
ensure_directory_exists() {
    local storage_dir=$(dirname "$iso_path")
    if [ ! -d "$storage_dir" ]; then
        echo -e "${CYAN}Storage directory $storage_dir does not exist. Creating...${NC}"
        mkdir -p "$storage_dir"
        if [ $? -ne 0 ]; then
            echo -e "${CYAN}Failed to create storage directory. Exiting.${NC}"
            exit 1
        fi
        echo -e "${CYAN}Directory created successfully.${NC}"
    fi
}

# --- // DL_ISO:
download_iso() {
    if ! wget -O "$iso_path" "$iso_url"; then
        echo -e "${CYAN}Download failed. Exiting.${NC}"
        rm -f "$iso_path"
        exit 2
    fi
    echo -e "${CYAN}Download complete.${NC}"
}

# --- // IDEMPOTENCY:
check_iso_existence() {
    if [ -f "$iso_path" ]; then
        echo -e "${CYAN}ISO for $distro already exists. Skipping download.${NC}"
    else
        ensure_directory_exists
        download_iso
    fi
}

# --- // CONFIG:
configure_bootloader() {
    case $bootloader in
        "grub")
            echo -e "${CYAN}Adding GRUB entry for $distro...${NC}"
            configure_grub
            ;;
        "systemd")
            echo -e "${CYAN}Adding systemd-boot entry for $distro...${NC}"
            configure_systemd_boot
            ;;
    esac
}

# --- // MAIN_LOGIC_LOOP:
escalate
dependencies
filesystem_type
setup_variables
check_bootloader
distrolist
check_iso_existence
configure_bootloader

if [ $? -eq 0 ]; then
    echo -e "${GREEN}Operation completed successfully. Please reboot to use the new ISO boot option.${NC}"
fi

All thoughts and suggestions for further improvement are welcome!

Last edited by 4ndr0666 (2024-04-12 06:11:49)

Offline

#3761 2024-04-12 08:06:26

Nebulosa
Member
Registered: 2009-08-24
Posts: 48

Re: Post your handy self made command line utilities

4ndr0666 wrote:

All thoughts and suggestions for further improvement are welcome!


Hint: please check your script at https://www.shellcheck.net/ there are a lot of errors there right now.

Functions:

1. dependencies(): curl and wget for what? If I'm using ext4 why do I need install btrfs-progs? Also curl, grep, sed, sha256sum, tee, cat, find, jq, btrfs are not used in the script.
2. distrolist(): Why list of distro is so huge? Have you tested all the urls yet? Many of them  is just lead to download page and don't download iso files. And if I select wrong option, it continues to run.
3. configure_bootloader(): There is no configure_grub and configure_systemd_boot in script.

Offline

#3762 2024-04-13 22:09:00

karabaja4
Member
From: Croatia
Registered: 2008-09-14
Posts: 1,001
Website

Re: Post your handy self made command line utilities

#!/bin/sh
set -eu
IFS='
'

_echo() {
    printf '\033[91m%s\033[0m\n' "${1}"
}

_src="${HOME}/ytdl.txt"
_wd="${HOME}/ytdl-tmp"
_dest="${HOME}/ytdl"

rm -vrf "${_wd}"
mkdir -vp "${_wd}"
mkdir -vp "${_dest}"

(
    cd "${_wd}"
    _echo "Running yt-dlp for: ${_src}"
    yt-dlp -a "${_src}" -o "%(title)s.%(ext)s" -v --extract-audio --audio-format best
    
    # clean up weird characters in file names
    _echo "Renaming files in: ${_wd}"
    perl-rename -v 's/[^a-zA-Z0-9](?![^.]*$)//g' ./*
    
    # increase volume for Huawei Watch GT 2 Pro
    for _original in ./*
    do
        if [ -f "${_original}" ]
        then
            _basename="$(basename "${_original}")"
            _mp3="yt-${_basename%%.*}.mp3"
            _echo "Converting ${_original} to ${_mp3}"
            ffmpeg -i "${_original}" -af 'volume=3' -codec:a libmp3lame -qscale:a 4 "${_mp3}"
            mv -v "${_mp3}" "${_dest}"
            rm -v "${_original}"
        fi
    done
)

# remove working dir
rm -vrf "${_wd}"

Script that reads YouTube links from $HOME/ytdl.txt and saves audio in mp3 format to $HOME/ytdl/. Depends on yt-dlp, perl-rename, ffmpeg.

It also increases volume by a factor of 3 using ffmpeg. This is because recently I've been taking long walks and listening podcasts on my smartwatch with bluetooth headphones, and audio on that thing is waaaay to low, I guess they were afraid of hearing damage or something.

Last edited by karabaja4 (2024-04-13 23:20:10)

Offline

#3763 2024-04-13 22:16:35

seth
Member
Registered: 2012-09-03
Posts: 58,698

Re: Post your handy self made command line utilities

Since yt audio is typically not mp3 but m4a or opus, you could fetch the native audio (-f140 will get you m4a, -F for a list of codecs) and add the gain while you're converting it to mp3 locally

Offline

#3764 2024-04-13 23:19:19

karabaja4
Member
From: Croatia
Registered: 2008-09-14
Posts: 1,001
Website

Re: Post your handy self made command line utilities

seth wrote:

Since yt audio is typically not mp3 but m4a or opus, you could fetch the native audio (-f140 will get you m4a, -F for a list of codecs) and add the gain while you're converting it to mp3 locally

Updated, thanks.

I added "--audio-format best" so whatever comes out (mp4a or opus) just gets picked up by ffmpeg and mp3 encoding happens only once (with added gain).

Offline

#3765 2024-05-17 15:37:07

EISENFELD
Member
From: Germany
Registered: 2024-03-13
Posts: 27
Website

Re: Post your handy self made command line utilities

#!/bin/bash
# LUSC - Linux UEFI STUB Creator
# 2024 by Lennart Martens - monkeynator78@gmail.com - https://github.com/lennart1978/LUSC -
# Automatically generate UEFI boot entries

# Color Codes
BLUE=$(tput setaf 4)
GREEN=$(tput setaf 2)
RED=$(tput setaf 1)
RESET=$(tput sgr0)

# Display usage information
usage() {
    cat << EOF
Usage: $(basename "$0")
This is a simple interactive tool to automatically generate UEFI boot entries.
It generates efibootmgr commands and exports them to a small executable.
No changes will be written to disk before confirmation.
The EFI partition must be mountet to /boot and the kernel -and initramfs image must be located at the root of it !
Some UEFI systems don't allow to create more than one EFI STUB entry.
Unfortunately efibootmgr is not able to change EFI entries. You always have to delete/overwrite entries to make changes happen.
Please don't use this Bash script when you don't exactly know what you are doing here and what EFI STUB means.
You can get some great info at : https://wiki.archlinux.org/title/EFISTUB 

And now good luck with EFI STUB booting.
L.Martens

Options:
    -h, --help      Display this help message
EOF
}

# Check if the script is running with root privileges
if [ "$UID" -ne 0 ]; then
    echo "${RED}This script must be run with root privileges !${RESET}"
    echo "type: sudo lusc -h for usage and more info."
    exit 1
fi

# Parse command-line arguments
while [[ $# -gt 0 ]]; do
    case "$1" in
        -h | --help)
            usage
            exit 0
            ;;
        *)
            echo "Unknown option: $1"
            usage
            exit 1
            ;;
    esac
    shift
done

# Prompt user to continue
echo "${BLUE}Welcome to LUSC - A Linux UEFI STUB Creator"
echo "-----------------------------------------"
echo "-----------------------------------------${RESET}"
read -r -p "Start creating UEFI boot entries ? (y/N) " choice
choice=$(echo "$choice" | tr '[:upper:]' '[:lower:]')
if [[ "$choice" != "y" ]]; then
    echo "Goodbye.Exiting..."
    exit 0
fi

# Prompt user to specify EFI partition
read -r -p "Please specify EFI partition (e.g., /dev/nvme0n1p1): " efi_partition

# Check if the EFI partition exists
if ! blkid | grep -q "$efi_partition"; then
    echo "${RED}Error: EFI partition '$efi_partition' not found !${RESET}"
    exit 1
fi

# Extract disk and partition number
efi_disk=$(echo "$efi_partition" | sed -E 's/p?[0-9]+$//')
efi_part_num=$(echo "$efi_partition" | grep -o '[0-9]*$')

# Prompt user to specify the label for the boot entry
read -r -p "Please specify the label for the boot entry (e.g., Arch Linux): " boot_label

# Detect partitions
efi_uuid=$(blkid -o value -s UUID "$efi_partition")
root_uuid=$(blkid -o value -s UUID "$(findmnt -no SOURCE /)")

# Check if swap partition exists
swap_uuid=$(blkid -o value -s UUID "$(findmnt -no SOURCE /swap)")
if [[ -z "$swap_uuid" ]]; then
    echo "${GREEN}No swap partition detected. Assuming Zswap is used.${RESET}"
fi

# Default kernel parameters
default_params="root=UUID=$root_uuid rw"
if [[ -n "$swap_uuid" ]]; then
    default_params="$default_params resume=UUID=$swap_uuid"
fi

# Prompt user to specify additional kernel parameters
echo "Current kernel parameters: $default_params"
echo "${GREEN}initrd and initrd-fallback will be added automatically !${RESET}"
echo "For example additional kernel parameters could be: quiet splash rootfstype=ext4 hostname=my-computer nohibernate noresume vm_debug=- ..."
read -r -p "Add additional kernel parameters (or press Enter to keep current): " extra_params

# Combine default and additional parameters
if [[ -n "$extra_params" ]]; then
    kernel_params="$default_params $extra_params"
else
    kernel_params="$default_params"
fi

# initramdisks with "\" !
initramdisk="\initramfs-linux.img"
initfallback="\initramfs-linux-fallback.img"

# Compose the command strings
linux_cmd="efibootmgr --create --disk $efi_disk --part $efi_part_num --label \"$boot_label\" --loader /vmlinuz-linux --unicode \"$kernel_params initrd=$initramdisk\" --verbose"
fallback_cmd="efibootmgr --create --disk $efi_disk --part $efi_part_num --label \"$boot_label (Fallback)\" --loader /vmlinuz-linux --unicode \"$kernel_params initrd=$initfallback\" --verbose"

# Print the commands for user confirmation
echo "Detected partitions:"
echo "EFI: $efi_partition ($efi_uuid)"
echo "Root: $(findmnt -no SOURCE /) ($root_uuid)"
if [[ -n "$swap_uuid" ]]; then
    echo "Swap: $(findmnt -no SOURCE /swap) ($swap_uuid)"
    resume_option="resume=UUID=$swap_uuid"
else
    resume_option=""
fi

echo
echo "Composed commands:"
echo "$linux_cmd"
echo "$fallback_cmd"


# Prompt user to write or execute commands
read -r -p "Create executable only, create and execute (sets UEFI boot entries), or abort? (c/ce/a) " action
action=$(echo "$action" | tr '[:upper:]' '[:lower:]')
case "$action" in
    c)
        # Write commands to file
        script_file="uefi_stub_gen_$(date "+%d-%-m-%Y--%H:%M")"
        {
            echo "#!/bin/bash"
            echo "# Generated UEFI boot entries by LUSC"
            echo "$fallback_cmd"   
            echo "$linux_cmd"     
            echo "exit 0"
            echo "# See 'man efibootmgr' for more information"
        } > "$script_file"
        chmod +x "$script_file"
        echo "Commands written to file: $script_file"
        ;;
    ce)
        # Write commands to file and execute
        script_file="uefi_stub_gen_$(date "+%d-%-m-%Y--%H:%M")"
        {
            echo "#!/bin/bash"
            echo "# Generated UEFI boot entries by LUSC"
            echo "$fallback_cmd"
            echo "$linux_cmd"
            echo "exit 0"
            echo "# See 'man efibootmgr' for more information"
        } > "$script_file"
        chmod +x "$script_file"
        echo "Commands written to file: $script_file"
        echo "Executing commands..."
        "./$script_file"
        echo "Changes written. Power off and restart (${RED}don't reboot !${RESET})."
        ;;
    a)
        echo "Aborted. No changes made."
        ;;
    *)
        echo "${RED}Invalid choice ! Aborting.${RESET}"
        ;;
esac

exit 0

My Script to easily create a working UEFI STUB bootentry. I tested it several times on different machines.
Feel free to adapt it to your special needs.

Last edited by EISENFELD (2024-05-17 15:38:05)


Ich weiß, dass ich nichts weiß !

Offline

#3766 2024-07-25 15:05:46

ugjka
Member
From: Latvia
Registered: 2014-04-01
Posts: 1,862
Website

Re: Post your handy self made command line utilities

Wireguard vpn toggler

package main

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"os/exec"
)

const (
	conf = "/etc/wireguard/wg0.conf"
)

var (
	on = []byte(`#AllowedIps = 10.111.222.0/24, fd2a:421:3819::/64
AllowedIPs = 0::/0, 0.0.0.0/0`)
	off = []byte(`AllowedIps = 10.111.222.0/24, fd2a:421:3819::/64
#AllowedIPs = 0::/0, 0.0.0.0/0`)
)

func main() {
	if len(os.Args) < 2 {
		fmt.Fprintln(os.Stderr, "try vpn on or off")
		os.Exit(1)
	}

	confdata, err := os.ReadFile(conf)
	if err != nil {
		log.Fatal(err)
	}

	switch os.Args[1] {
	case "on":
		if bytes.Contains(confdata, on) {
			fmt.Fprintln(os.Stderr, "vpn already on!")
			os.Exit(1)
		}
		confdata = bytes.Replace(confdata, off, on, 1)
	case "off":
		if bytes.Contains(confdata, off) {
			fmt.Fprintln(os.Stderr, "vpn already off!")
			os.Exit(1)
		}
		confdata = bytes.Replace(confdata, on, off, 1)
	default:
		fmt.Fprintf(os.Stderr, "invalid command: %s\n", os.Args[1])
		os.Exit(1)
	}

	err = os.WriteFile(conf, confdata, 0600)
	if err != nil {
		log.Fatal(err)
	}

	err = exec.Command("systemctl", "restart", "wg-quick@wg0.service").Run()
	if err != nil {
		log.Fatal(err)
	}
}

Last edited by ugjka (2024-07-25 15:14:11)


https://ugjka.net
paru > yay | vesktop > discord
pacman -S spotify-launcher
mount /dev/disk/by-...

Offline

#3767 2024-07-25 19:13:30

Awebb
Member
Registered: 2010-05-06
Posts: 6,602

Re: Post your handy self made command line utilities

ugjka wrote:

Wireguard vpn toggler

Mind adding the language?

EDIT: Figured it out.

Last edited by Awebb (2024-07-25 19:14:54)

Offline

#3768 2024-07-25 19:23:07

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 30,330
Website

Re: Post your handy self made command line utilities

It looks like that just adds/removes a single hash mark to a given line of a file.  That could be a sed one-liner to really just toggle it, or perhaps just a few lines more to accept off/on parameters.

EDIT: E.g., completely untested as I don't have the relevant target file:

config=/path/to/target/file
case "$1" in
   on) sed i '/AllowedIps/{s/^/#/;s/, #/,/}' $config ;;
   off) sed i '/#AllowedIps/{s/^#//;s/, /, #/}' $config ;;
   toggle) sed i '/#AllowedIps/{s/^#//;s/, /, #/;ba;};/AllowedIps/{s/^/#/;s/, #/,/;};:a' $config ;;
esac
# add systemctl restart ...

Last edited by Trilby (2024-07-25 19:37:25)


"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman

Offline

#3769 2024-07-26 16:14:17

EISENFELD
Member
From: Germany
Registered: 2024-03-13
Posts: 27
Website

Re: Post your handy self made command line utilities

A CLI snake game in C.
Dependency: ncurses
Compile: gcc main.c -o playsnake -lncurses
Run: ./playsnake

#include <ncurses.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <stdbool.h>

#define MAX_LENGTH 100
#define SPEED 50000
#define SNAKE_CHAR '#'
#define FOOD_CHAR '0'

typedef struct {
    int x, y;
} Point;

int maxx, maxy, food_x, food_y, score;
Point snake[MAX_LENGTH];
int length = 3;
enum direction { UP, DOWN, LEFT, RIGHT };
enum direction dir = RIGHT;
bool is_eaten = false;

void print_score()
{
    attron(COLOR_PAIR(2));
    mvprintw(maxy - 1, 0, "Score: %3d | Press esc to exit", score);
    attroff(COLOR_PAIR(2));
}

void init_game() {
    score = 0;
    initscr();
    cbreak();
    noecho();
    curs_set(0);
    keypad(stdscr, TRUE);
    nodelay(stdscr, TRUE);
    start_color();
    init_pair(1, COLOR_CYAN, COLOR_BLACK);
    init_pair(2, COLOR_WHITE, COLOR_BLACK);
    init_pair(3, COLOR_RED, COLOR_BLACK);
    init_pair(4, COLOR_GREEN, COLOR_BLACK);
    init_pair(5, COLOR_YELLOW, COLOR_BLACK);
    init_pair(6, COLOR_BLUE, COLOR_BLACK);
    init_pair(7, COLOR_MAGENTA, COLOR_BLACK);

    maxx = getmaxx(stdscr);
    maxy = getmaxy(stdscr);

    srand(time(NULL));
    snake[0].x = maxx / 4;
    snake[0].y = maxy / 2;
    snake[1].x = snake[0].x - 1;
    snake[1].y = snake[0].y;
    snake[2].x = snake[1].x - 1;
    snake[2].y = snake[1].y;

    food_x = rand() % (maxx - 2) + 1;
    food_y = rand() % (maxy - 2) + 1;
}

void draw_snake() {
    attron(COLOR_PAIR(4));
    for (int i = 0; i < length; i++) {
        mvaddch(snake[i].y, snake[i].x, SNAKE_CHAR);
    }
    attroff(COLOR_PAIR(4));
}

void draw_food() {
    attron(COLOR_PAIR(5));
    mvaddch(food_y, food_x, FOOD_CHAR);
    attroff(COLOR_PAIR(5));
}

void move_snake() {
    for (int i = length - 1; i > 0; i--) {
        snake[i] = snake[i - 1];
    }
    switch (dir) {
        case UP:
            snake[0].y--;
            break;
        case DOWN:
            snake[0].y++;
            break;
        case LEFT:
            snake[0].x--;
            break;
        case RIGHT:
            snake[0].x++;
            break;
    }
    // if snake reaches the edge, it will come from the other side
   if(snake[0].x >= maxx)
   {
        snake[0].x = 1;
   }
   if(snake[0].x <= 0)
   {
        snake[0].x = maxx - 1;
   }
   if(snake[0].y >= maxy)
   {
        snake[0].y = 1;
   }
   if(snake[0].y <= 0)
   {
        snake[0].y = maxy - 1;
   }
}

bool check_collision() {
    for (int i = 1; i < length; i++) {
        if (snake[i].x == snake[0].x && snake[i].y == snake[0].y) {
            return true;
        }
    }   
   return false;
}

void check_food() {
    if (snake[0].x == food_x && snake[0].y == food_y) {
        is_eaten = true;
        length++;
        score += 10;
        food_x = rand() % (maxx - 2) + 1;
        food_y = rand() % (maxy - 2) + 1;
    }
}

void handle_input() {
    int ch = getch();
    switch (ch) {
        case KEY_UP:
            if (dir != DOWN) dir = UP;
            break;
        case KEY_DOWN:
            if (dir != UP) dir = DOWN;
            break;
        case KEY_LEFT:
            if (dir != RIGHT) dir = LEFT;
            break;
        case KEY_RIGHT:
            if (dir != LEFT) dir = RIGHT;
            break;
        case 27: // ESC
            endwin();
            exit(0);
        default:
            break;
    }
}

void game_over() {
    clear();
    attron(COLOR_PAIR(3));
    attron(A_BOLD);
    mvprintw(maxy / 2, maxx / 2 - 40, "Game Over! Press ESC to exit. %d Points", score);
    attroff(COLOR_PAIR(4));
    attroff(A_BOLD);
    score = 0;
    length = 3;
    dir = RIGHT;
    refresh();
    sleep(2);
}

int main() {
    init_game();

    while (true) {
        clear();
        print_score();
        handle_input();
        move_snake();
        check_food();
        draw_food();
        draw_snake();
        if (check_collision()) {
            game_over();
            init_game();
            continue;
        }
        refresh();
        usleep(SPEED);
    }

    endwin();
    return 0;
}

For the smallest possible binary size, you can use "strip -s playsnake && upx -9 playsnake".
(UPX = Ultimate Packer for Executables)
Then this tiny command line game will be about 8,3 KB !
enjoy ;-)


Ich weiß, dass ich nichts weiß !

Offline

#3770 2024-07-27 12:08:34

256
Member
Registered: 2023-12-17
Posts: 14

Re: Post your handy self made command line utilities

EISENFELD wrote:

A CLI snake game in C.

I wrote the same sort of thing a few months ago, in March. I used C89.

#include <ncurses.h>
#include <unistd.h> /* usleep() */
#include <stdlib.h> /* rand() */
#include <time.h> /* To seed rand(). */

enum colour {
        BACKGROUND = 1,
        HEAD,
        TAIL,
        FOOD
};

int w, h; /* Width and height of game-space. */
int x, y, tx, ty; /* Head location, tail location. */
int surplus = 0; /* Extra length of tail to grow. Usually 0; 1 if food eaten. */
enum {UP, LEFT, DOWN, RIGHT} dir;
char *board; /* Bits 5-7 store type, 3-4 store direction. (Bit 0 is MSB). */

void draw_head(void){
        const char dirs[] = "^<v>";

        attron(COLOR_PAIR(HEAD));
        mvaddch(y, x, dirs[dir]);
        board[y * w + x] = HEAD | (dir<<3);
}

void undraw_head(void){ /* Turn snake's head into tail section. */
        attron(COLOR_PAIR(TAIL));
        mvaddch(y, x, '+');
        board[y * w + x]++; /* Convert from HEAD (2) to TAIL (3). */
}

void retract_tail(void){
        int tdir;

        attron(COLOR_PAIR(BACKGROUND));
        mvaddch(ty, tx, ' ');
        tdir = board[ty * w + tx] >> 3;
        board[ty * w + tx] = 0;
        switch(tdir){
        case UP:    ty--; break;
        case LEFT:  tx--; break;
        case DOWN:  ty++; break;
        case RIGHT: tx++; break;
        }
}

void place_food(void){
        int fx, fy;

        do {
                fx = rand() % w;
                fy = rand() % h;
        } while(board[fy * w + fx]);
        attron(COLOR_PAIR(FOOD));
        mvaddch(fy, fx, 'X');
        board[fy * w + fx] = FOOD;
}

void turn(int new_dir){
        dir = new_dir;
        board[y * w + x] &= 7;
        board[y * w + x] |= dir << 3;
        draw_head();
}

int game_tick(void){
        int nx = x, ny = y; /* New x,y. */

        switch(dir){
        case UP:    ny--; break;
        case LEFT:  nx--; break;
        case DOWN:  ny++; break;
        case RIGHT: nx++; break;
        }
        if(nx < 0 || nx >= w || ny < 0 || ny >= h)
                return 1; /* GAME OVER; hit wall. */
        if(board[ny * w + nx] == FOOD){
                surplus++; /* sur+++ lol */
                place_food();
        } else if(board[ny * w + nx])
                return 1; /* GAME OVER; hit self. */
        undraw_head();
        x = nx, y = ny;
        draw_head();
        if(surplus <= 0)
                retract_tail();
        else
                surplus--;
        attron(COLOR_PAIR(HEAD));
        return 0;
}

void game_over(void){
        int score;

        for(score = 0;board[ty * w + tx]&7 != HEAD;score++)
                retract_tail(), refresh(), usleep(100000);
        endwin();
        printf("SCORE: %d\n", score);
        while(getch() != ERR)
                ; /* Prevent keypresses from reaching shell after exit. */
        exit(0);
}

void game_loop(void){
        while(1){
                switch(getch()){
                case KEY_UP:    turn(UP);    break;
                case KEY_LEFT:  turn(LEFT);  break;
                case KEY_DOWN:  turn(DOWN);  break;
                case KEY_RIGHT: turn(RIGHT); break;
                }
                if(game_tick())
                        game_over(); /* Function does not return. */
                usleep(1000000 / 20); /* 20FPS. */
        }
}

void start_game(void){
        board = calloc(w, h);
        clear();
        tx = x = rand() % w;
        ty = y = rand() % h;
        dir = rand() % 4;
        draw_head();
        place_food();
        game_loop();
}

int main(){

        srand(time(NULL));
        initscr();
        curs_set(0);
        cbreak();
        keypad(stdscr, TRUE);
        nodelay(stdscr, TRUE);
        noecho();
        getmaxyx(stdscr, h, w);

        start_color();
        init_pair(BACKGROUND, COLOR_WHITE, COLOR_BLACK);
        init_pair(HEAD, COLOR_YELLOW, COLOR_BLACK);
        init_pair(TAIL, COLOR_GREEN, COLOR_BLACK);
        init_pair(FOOD, COLOR_GREEN, COLOR_MAGENTA);
        start_game();
        endwin();
}

It's interesting to see the similarities and differences in how we did the same thing. We both had an enum for direction with the exact same members (in a different order), although unlike you I didn't bother to give it a name (which I think makes sense, since neither of us used it more than once). We both used "srand(time(NULL));" verbatim. The biggest difference is in how we encode the game environment.

Your snake is a set of (x,y) coordinates, and likewise for food. My game world, though, is a COLS*ROWS array covering the entire terminal. The game state is encoded almost entirely by this array. I probably had cellular automata on the mind. This has the effect that, unlike yours, my game doesn't write to incorrect memory locations when the snake is longer than 100 characters.

My first score (when I actually tried to play properly) was 1320. At 1000, I started noticing that getting a food item causes a blank space to appear in the snake, which remains until the tail moves past it. It seems to always first appear at the same amount of characters behind the head. It obviously has to do with MAX_LENGTH, but I have no idea how exactly it happens.

I don't think using ESC as an input key is a good idea, by the way. Some (all?) terminals seem to wait for a bit before allowing the keypress to go through; I think this is because it's used as an alternative to the ALT key. I changed it to 'q' and it became instant.

Using bare number literals for colours makes your code more confusing.

Also, yours flickers because you redraw the screen every time. And when food is collected, you increment the length, but you don't actually fill in the new position in snake[], so it defaults to (0,0), which means that for a brief moment, a snake tail section appears at the top left.

Also also in your game, food items can appear anywhere, including in the snake. And there's errant whitespace at the end of line 119 (my syntax highlighting makes this obvious).

It would be interesting to see if anyone else here has implemented the same thing.


"Don't comment bad code - rewrite it." - The Elements of Programming Style (1978), Brian W. Kernighan & P. J. Plauger, p. 144.

Offline

#3771 2024-07-27 13:16:57

EISENFELD
Member
From: Germany
Registered: 2024-03-13
Posts: 27
Website

Re: Post your handy self made command line utilities

Your game is very well done, but the level of difficulty is much higher than mine. The snake dies when it hits the edge ;-)
Yes, the flickering is a problem, but I don't have that inside the terminal of VS Code. I just noticed this in the normal terminal.
There are still some problems in my code, you are right. I just started to code in C again after many years, so I am not very good, I still have to learn a lot...
I switched to GoLang some time ago and now back to good old C again.


Ich weiß, dass ich nichts weiß !

Offline

#3772 2024-07-28 14:49:22

ugjka
Member
From: Latvia
Registered: 2014-04-01
Posts: 1,862
Website

Re: Post your handy self made command line utilities

Trilby wrote:

It looks like that just adds/removes a single hash mark to a given line of a file.  That could be a sed one-liner to really just toggle it, or perhaps just a few lines more to accept off/on parameters.

EDIT: E.g., completely untested as I don't have the relevant target file:

config=/path/to/target/file
case "$1" in
   on) sed i '/AllowedIps/{s/^/#/;s/, #/,/}' $config ;;
   off) sed i '/#AllowedIps/{s/^#//;s/, /, #/}' $config ;;
   toggle) sed i '/#AllowedIps/{s/^#//;s/, /, #/;ba;};/AllowedIps/{s/^/#/;s/, #/,/;};:a' $config ;;
esac
# add systemctl restart ...

Looks like  some voodoo but that gave me the idea to write more correct version

package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"regexp"
	"slices"
)

const (
	conf = "/etc/wireguard/wg0.conf"
)

var (
	on  = regexp.MustCompile(`(?mis)(#AllowedIPs).+(AllowedIPs).+`)
	off = regexp.MustCompile(`(?mis)(AllowedIPs).+(#AllowedIPs).+`)
)

func main() {
	if len(os.Args) < 2 {
		fmt.Fprintln(os.Stderr, "try vpn on or off")
		os.Exit(1)
	}

	confdata, err := os.ReadFile(conf)
	if err != nil {
		log.Fatal(err)
	}

	switch os.Args[1] {
	case "on":
		if on.Match(confdata) {
			fmt.Fprintln(os.Stderr, "vpn already on!")
			os.Exit(1)
		}
		i := off.FindSubmatchIndex(confdata)
		confdata = slices.Delete(confdata, i[4], i[4]+1)
		confdata = slices.Insert(confdata, i[2], byte('#'))
	case "off":
		if off.Match(confdata) {
			fmt.Fprintln(os.Stderr, "vpn already off!")
			os.Exit(1)
		}
		i := on.FindSubmatchIndex(confdata)
		confdata = slices.Insert(confdata, i[4], byte('#'))
		confdata = slices.Delete(confdata, i[2], i[2]+1)
	default:
		fmt.Fprintf(os.Stderr, "invalid command: %s\n", os.Args[1])
		os.Exit(1)
	}

	err = os.WriteFile(conf, confdata, 0600)
	if err != nil {
		log.Fatal(err)
	}

	err = exec.Command("systemctl", "restart", "wg-quick@wg0.service").Run()
	if err != nil {
		log.Fatal(err)
	}
}

@Awebb it is go, yes


https://ugjka.net
paru > yay | vesktop > discord
pacman -S spotify-launcher
mount /dev/disk/by-...

Offline

#3773 2024-07-28 16:04:52

seth
Member
Registered: 2012-09-03
Posts: 58,698

Re: Post your handy self made command line utilities

Since you've to restart the service anyway, why don't you just switch between wg-quick@wg0.service and wg-quick@wg0_novpn.service and use static configs instead of relying on string matches?

Offline

#3774 2024-07-28 16:09:18

ugjka
Member
From: Latvia
Registered: 2014-04-01
Posts: 1,862
Website

Re: Post your handy self made command line utilities

seth wrote:

Since you've to restart the service anyway, why don't you just switch between wg-quick@wg0.service and wg-quick@wg0_novpn.service and use static configs instead of relying on string matches?

Ah yes, the voice of sanity! Well, i simply replicated what what i was doing by hand, that's all... I didn't really think it through, now did i? smile


https://ugjka.net
paru > yay | vesktop > discord
pacman -S spotify-launcher
mount /dev/disk/by-...

Offline

#3775 2024-07-30 18:52:55

Awebb
Member
Registered: 2010-05-06
Posts: 6,602

Re: Post your handy self made command line utilities

People are too busy to dodge systemd to actually use it :-D

Offline

Board footer

Powered by FluxBB