You are not logged in.

#3726 2023-08-16 05:48:25

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

Re: Post your handy self made command line utilities

Trilby wrote:

Couldn't you acheive the same goal by just looking for broken links:

find -L /etc/systemd/ -type l

...and I could then feed this to pkgfile, in case I really want to know where the link came from. Nice.

Last edited by Awebb (2023-08-16 05:51:38)

Offline

#3727 2023-08-20 23:09:51

vikramr
Member
Registered: 2009-09-22
Posts: 45

Re: Post your handy self made command line utilities

Small script to calculate when I should  start charging my EV to make sure  its ready by 8:00 AM.

#!/bin/bash
#in kwh
battery_capacity=60
#in kw
charge_rate=2.8
charge_complete_time=8
current_battery_level=$1

if [[ $# -ne 1 ]]; then
    echo 'Too many/few arguments, expecting one' >&2
    exit 1
fi

if [[ $(echo "if (( $current_battery_level < 0 ) || ( $current_battery_level > 1 )) 1 else 0" | bc) -eq 1 ]]

then
	echo "current charge level must be between 0 and 1"
	exit 1
fi

echo "
	scale=2;
	print \"current charge level=  \" ; $current_battery_level;
	charge_duration=$battery_capacity*(1 - $current_battery_level)/$charge_rate;
	print \"charge_duration = \" ;charge_duration;
	charge_complete_time=$charge_complete_time
	print \"target complete time = \" ;charge_complete_time;
	start_time=charge_complete_time-charge_duration - 1;
	if (start_time <= 0) start_time +=24;
	print \"start_time = \"; start_time;"	|  bc

Offline

#3728 2023-08-27 18:43:13

snakeroot
Member
Registered: 2012-10-06
Posts: 168

Re: Post your handy self made command line utilities

Script to delete orphaned packages (and their configs) but retain packages installed as makedepends for AUR builds. On a measure-twice-cut-once basis, it can be used to list orphans cum makedepends, makedepends and orphans ex makedepends in lieu of actually deleting.

This works on the assumption that the .SRCINFO for AUR packages is kept in /home/AUR/builds/cache/<pkgname>/ and the variable AUR_SRCINFO may need to be modified accordingly.

#! /bin/bash

AUR_SRCINFO='/home/AUR/builds/cache/*/.SRCINFO'
MAKEDEPENDS=$(mktemp)
ORPHANS=$(mktemp)
TRUE_ORPHANS=$(mktemp)

for i in ${AUR_SRCINFO}; do
        if sed -n '/pkgname/ s/^pkgname = //p' "${i}" | pacman -Qi - > /dev/null 2>&1 ; then
                sed -n '/makedepends/ s/^.*makedepends = //p' ${i} >> "${MAKEDEPENDS}"
        fi
done
sort -u "${MAKEDEPENDS}" -o "${MAKEDEPENDS}"
pacman -Qqtd > "${ORPHANS}"
grep -Fvxf "${MAKEDEPENDS}" "${ORPHANS}" > "${TRUE_ORPHANS}"
case ${1} in
        "M")
                echo "makedepends packages:"
                cat "${MAKEDEPENDS}"
        ;;
        "O")
                echo "orphaned and makedepends packages:"
                cat "${ORPHANS}"
        ;;
        "R")
                echo "Removing true orphaned packages and their config files and dependencies"
                cat "${TRUE_ORPHANS}" | pacman -Rns -
        ;;
        "T")
                echo "true orphaned packages:"
                cat "${TRUE_ORPHANS}"
        ;;
        *)
                echo "Parameters:"
                echo "M for makedepends packages"
                echo "O for orphaned and makedepends packages"
                echo "R to remove true orphaned packages and their config files and dependencies. THIS MUST BE RUN AS ROOT"
                echo "T for true orphaned packages"
        ;;
esac
rm "${MAKEDEPENDS}"
rm "${ORPHANS}"
rm "${TRUE_ORPHANS}"

Offline

#3729 2023-09-16 23:45:14

sweet_tea
Member
Registered: 2022-12-29
Posts: 7

Re: Post your handy self made command line utilities

An interactive Yes/No script similar to fzf, gum choose / gum confirm. Entirely in bash.

#!/bin/bash
# simple script for an interactive YES/NO prompt
# set -x

menu() {
    tput civis
    index=0
    def="Continue? "
    clear
    key="j"

    prompt="${1:-$def}"
    prompt2="${2:-}"

    while true; do
        tput cup 0 0 && printf '\e[35m%s\e[0m\n' "${prompt}"
        tput cup 1 0 && printf '\e[33m%s\n' "${prompt2}"
    if ((index == 1)); then
        tput cup 2 0 && printf '\e[2k' && printf '\e[31m%s\e[0m\n' "> Yes"
        tput cup 3 0 && printf '\e[2k' && printf '\e[32m%s\e[0m\n' "  No"
    elif ((index == 0)); then
        tput cup 2 0 && printf '\e[2k' && printf '\e[32m%s\e[0m\n' "  Yes"
        tput cup 3 0 && printf '\e[2k' && printf '\e[31m%s\e[0m\n' "> No"
    fi

        
        case "$key" in
            j|$'\x1b\x5b\x41') if [[ "$index" = 0 ]]; then index=1 ; elif [[ "$index" = 1 ]]; then index=0 ; fi ;;
            k|$'\x1b\x5b\x42') if [[ "$index" = 0 ]]; then index=1 ; elif [[ "$index" = 1 ]]; then index=0 ; fi ;;
            $'\x0a') break ;;
            *) echo >/dev/null ;;
        esac

        unset K1 K2 K3
        read -sN1
        K1="$REPLY"
        read -sN2 -t 0.001
        K2="$REPLY"
        read -sN1 -t 0.001
        K3="$REPLY"
        key="$K1$K2$K3"

    done
    # index will be 1 or 0 which is also return codes for success and fail
    # used for the last condition on whether to start the game or not
    stty sane
    echo "$index"
    return "$index"
}

cleanup() {
    # clear
    tput cnorm
    stty echo
}

trap cleanup EXIT

menu "${@}"

Improvements and advice welcomed

Last edited by sweet_tea (2023-09-16 23:51:25)

Offline

#3730 2023-09-18 10:54:16

Docbroke
Member
From: India
Registered: 2015-06-13
Posts: 1,438

Re: Post your handy self made command line utilities

Wrapper around bluetoothctl

#!/bin/bash

ACTION() {
echo "Choose device using id"
read id
echo "What do you want to do?
provide space separated command/s
pair unpair trust untrust connect disconnect remove"
read action

xdotool search --name blue && xdotool windowclose $(xdotool search --name blue)

for x in $action; do
	bluetoothctl "$x" "$id"
done
}

bluetoothctl devices
echo "choose what to do?
a. act on known device b. scan for new"
read ans
if [[ $ans = a ]]; then
    ACTION
else
    lxterminal -t blue --geometry=70x15 -e bluetoothctl scan on
    ACTION
fi

Offline

#3731 2023-11-29 13:24:03

Wild Penguin
Member
Registered: 2015-03-19
Posts: 347

Re: Post your handy self made command line utilities

Quite simple, but - list packages by repo (for, say, re-installation, or to help to remember removing clutter). Pretty much made using the wiki!

#!/bin/bash

OUTDIR=pacmanlists
OUTFILE=explicit.lst # edit name to your liking

until [ -z "$1" ] ; do
        case $1 in
                -d)
                        OUTDIR="$2"
                        shift
                        shift
                        ;;
                -f)
                        OUTFILE="$2"
                        shift
                        shift
                        ;;
                *)
                        echo unknown parameter $1
                        exit 1
                        ;;
        esac
done

myerrorfunc () {
        echo $1
        exit 1
}


# List explicitly installed packages from repo $1
list_repo_explicit () {
        comm -12 <(pacman -Qqe | sort) <(pacman -Sql $1 | sort)
}

if [ ! -e $OUTDIR ] ; then 
        mkdir "$OUTDIR" || myerrorfunc "can not mkdir $OUTDIR"
elif [ -e "$OUTDIR" -a ! -d "$OUTDIR" ] ; then
        myerrorfunc "$OUTDIR exist but not a dir!"
fi

# list ALL explicitly installed packages; TODO: remove base group!
pacman -Qqe > ${OUTFILE}

# explicitly installed
pacman -Qqe  > ${OUTDIR}/${OUTFILE}
# Orphans 
pacman -Qtdq > ${OUTDIR}/orphans_${OUTFILE}
# External (often: packages deleted from repos)
pacman -Qqem > ${OUTDIR}/externalpkgs_${OUTFILE}

# list the repos you want to list into separate files here:
for REPO in core extra multilib archzfs custom ; do
        list_repo_explicit $REPO > ${REPO}_$OUTFILE 
done

Ideas/TODO:

  1. put to cron (say, weekly?).

  2. Send periodic reminders to sysadmin about line count(s) of these files!

EDIT: Improved the script a bit and corrected errors

Last edited by Wild Penguin (2023-12-05 10:58:03)

Offline

#3732 2023-12-07 16:23:36

papajoke
Member
From: france
Registered: 2014-10-10
Posts: 40

Re: Post your handy self made command line utilities

Script for display archlinux bugs

Why ? I want packages name (hard to read on gitlab) et want a filter for only packages installed on my arch

It's only for archlinux gitlab users wink use a TOKEN
return are as:

python-pandas: Importing pandas crashes python with SIGILL on AMD A6-7310       2022-01-30  (2) (3)
  2-high confirmed
  https://gitlab.archlinux.org/archlinux/packaging/packages/python-pandas/-/issues/1

linux: ntfs3 module flushes changes to files only on unmount    2023-11-18  (4) (38)
  3-medium waiting
  https://gitlab.archlinux.org/archlinux/packaging/packages/linux/-/issues/6

mesa: radeonsi python-pytorch ROCm segfaults    2023-11-22  (3) (3)
  4-low confirmed
  https://gitlab.archlinux.org/archlinux/packaging/packages/mesa/-/issues/3

usage: arch-issues [-h] [-p {1,2,3,4,5}] [-n N] [-f] [-r] [-s] [-c] [SEARCH_TEXT]
options:
  -p {1,2,3,4,5}  Minimum severity (default: lowest)  # display filter only
  -n 25            Bugs to load (maximum: 100)
  -f, --filter    Display Only package installed
  -r, --reversed  Display order by date created

Positional argument = text to search


snippet

#!/usr/bin/env python

import argparse
from enum import Enum
import json
import os
from pathlib import Path
from urllib import request, error
import sys

TOKEN = os.getenv('API_GITLAB_ARCH', "XXXX-XXXXXXXXXXXXXXX")


class Colors(Enum):
    BLUE = '\033[94m'
    GREEN = '\033[92m'
    WARNING = '\033[93m'
    FAIL = '\033[91m'
    GRAY = '\033[90m'
    SOMBRE = '\033[96m'
    ENDC = '\033[0m'
    BOLD = '\033[1m'

    def format(self, text) -> str:
        return f"{self.value}{text}{self.ENDC.value}"


class Severities(Enum):
    critical = 1
    high = 2
    medium = 3
    low = 4
    lowest = 5

    @classmethod
    def from_txt(cls, txt):
        return cls(int(txt[0]))

    def __str__(self):
        return f"{self.value}-{self.name}"


def format_severity(severity: Severities) -> str:
    if severity.value < 3:
        return Colors.FAIL.format(severity)
    return str(severity)


def download(search: str, count: int, severity_mini: int) -> list:
    search = f"&search={search}" if search else ""
    count = count if count < 101 else 25
    url = f"https://gitlab.archlinux.org/api/v4/groups/11323/issues?scope=all&sort=desc{search}&order_by=created_at&state=opened&per_page={count}&page=1&labels=scope::bug"
    # url = url + ",severity::1-critical,severity::2-high,severity::3-medium" # TODO ?
    hdr = {"PRIVATE-TOKEN": TOKEN, "User-Agent": "Arch-issues/1.0 (archlinux; Linux)"}
    req = request.Request(url, headers=hdr)
    try:
        with request.urlopen(req) as response:
            return json.loads(response.read())
    except (error.HTTPError, error.URLError) as err:
        print("Web error:", err)
    return []


def get_package_name(url: str) -> str:
    url = url.removeprefix("https://gitlab.archlinux.org/archlinux/packaging/packages/")
    return url.split("/", maxsplit=2)[0]


def get_labels(labels: list):
    ret = ['', '']
    for label in labels:
        if label.startswith("severity::"):
            ret[0] = Severities.from_txt(label[10:])
        elif label.startswith("status::"):
            ret[1] = label[8:]
    return ret[0], ret[1]


def my_packages():
    for dir in Path("/var/lib/pacman/local/").iterdir():
        parts = dir.name.split("-")
        if len(parts) < 3:
            continue
        yield "-".join(parts[:len(parts)-2])


if __name__ == "__main__":

    parser = argparse.ArgumentParser(
                    prog="arch-issues",
                    description="Archlinux bugtracker",
                    epilog="Positional argument = text to search",
    )
    parser.add_argument("-p", type=int, choices=[x.value for x in Severities], default=Severities.lowest.value, help="Minimum severity (default: lowest)")
    parser.add_argument("-n", type=int, default=25, help="Bugs to load (maximum: 100)")
    parser.add_argument("-f", "--filter", action="store_true", help="Only package installed", default=False)
    parser.add_argument("-r", "--reversed", action="store_true", help="Display order by date created", default=False)
    # -s , -c : only for dev
    parser.add_argument("-s", "--save", action="store_true", help="Save in cache", default=False)
    parser.add_argument("-c", "--cache", action="store_true", help="Use cache", default=False)
    args, search = parser.parse_known_args()
    search = " ".join(search)

    datas = []
    # exit(0)

    if not args.cache:
        datas = download(search, args.n, args.p)
    else:
        with open("arch.issues.json") as fjson:
            datas = json.load(fjson)

    if not datas:
        exit(2)

    if args.save:
        with open("arch.issues.json", "w") as fjson:
            fjson.write(json.dumps(datas, indent=2))

    if args.filter:
        packages = tuple(my_packages())

    for item in sorted(datas, key=lambda x: x["created_at"], reverse=args.reversed):
        severity, status = get_labels(item['labels'])
        if severity.value > args.p:
            continue
        pkg = get_package_name(item['web_url'])
        if args.filter and pkg not in packages:
            # print("# NO", pkg)
            continue
        print()
        severity = format_severity(severity)
        nb_assign = len(item['assignees'])
        nb_assign = f"{nb_assign}" if nb_assign > 0 else ''
        # `user_notes_count` == responses in issue
        print(
            f"{Colors.BOLD.format(pkg)}:",
            f"{Colors.BLUE.format(item['title'])}",
            f"\t{item['created_at'][0:10]}",
            f" ({nb_assign}) ({item['user_notes_count'] if item['user_notes_count'] else ''})"
        )
        print(f"  {severity} {status}")
        print(f"  {Colors.GRAY.format(item['web_url'])}")

thanks to this topic for the idea


lts - zsh - Kde - Intel Core i3 - 6Go RAM - GeForce 405 video-nouveau

Offline

#3733 2023-12-09 09:11:26

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

Re: Post your handy self made command line utilities

gist

// IRC text-to-speech server
// needs ffmpeg and piper-tts (https://github.com/rhasspy/piper)
//
// Example stream:
// https://ugjka.net/irc-radio/
// mpv https://ugjka.net/ircradio
// mpg123 https://ugjka.net/ircradio
//
// configuration? change the constants and build
package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"net/http"
	"net/mail"
	"net/url"
	"os"
	"os/exec"
	"strings"
	"sync"
	"time"

	"github.com/bogem/id3v2/v2"
	"github.com/tcolgate/mp3"
	kitty "github.com/ugjka/kittybot"
	"gopkg.in/inconshreveable/log15.v2"
	"mvdan.cc/xurls/v2"
)

const IRC_SERVER = "irc.libera.chat:6697"
const IRC_NICK = "guest556677"
const IRC_PASSWORD = ""

var IRC_CHANNELS = []string{
	"##english",
	"#android",
	"#archlinux",
	"#archlinux-offtopic",
	"#bash",
	"#go-nuts",
	"#kde",
	"#kde-devel",
	"#libera",
	"#linux",
	"#linux-offtopic",
	"#networking",
	"#newpipe",
	"#nextcloud",
	"#security",
	"#systemd",
	"#ubuntu",
	"#ubuntu-server",
	"#ubuntu-offtopic",
	"#yt-dlp",
	"#ugjka",
}

const PIPER_TTS_VOICE = "/home/ugjka/amy/medium/en_US-amy-medium.onnx"

// Silence PCM
const SPR = 22050
const PCM_SECOND = SPR * 2
const PCM_BUFFER = PCM_SECOND / 10
const PCM_BUFFER_DUR = time.Second / 10

// Mp3

const BITRATE = 40

// Buffers
const INIT_BUFF_SEC = 15 //seconds
const INIT_BUFF = BITRATE * 1000 / 8 * INIT_BUFF_SEC
const NETW_BUFF = INIT_BUFF / 4
const WORK_BUFF = INIT_BUFF / 32
const MAX_BACKLOG = INIT_BUFF * 2

const STREAM_PORT = 8089

// TMP DIR
const TMP_FOLDER = "ircwebradiotmp"

var tmpdb = newFiles()

var log = log15.New()

var start = make(chan struct{})

func main() {
	exes := []string{"piper-tts", "ffmpeg"}
	for _, exe := range exes {
		_, err := exec.LookPath(exe)
		errExit(err)
	}

	os.RemoveAll(TMP_FOLDER)
	err := os.Mkdir(TMP_FOLDER, 0755)
	errExit(err)
	err = os.Chdir(TMP_FOLDER)
	errExit(err)

	if len(os.Args) > 1 {
		IRC_CHANNELS = []string{"#" + os.Args[1]}
	}

	bot := kitty.NewBot(IRC_SERVER, IRC_NICK,
		func(bot *kitty.Bot) {
			bot.Password = IRC_PASSWORD
			bot.Channels = IRC_CHANNELS
			bot.SSL = true
		},
	)
	h := log15.StreamHandler(
		os.Stderr,
		log15.FormatFunc(
			func(r *log15.Record) []byte {
				buf := bytes.NewBuffer(nil)
				fmt.Fprintf(buf, "[%v] ", r.Lvl)
				fmt.Fprintf(buf, "[%v] ", r.Msg)
				for i, v := range r.Ctx {
					if i%2 == 0 {
						fmt.Fprintf(buf, "%v=", v)
					} else {
						fmt.Fprintf(buf, "%v ", v)
					}
				}
				fmt.Fprintln(buf)
				return buf.Bytes()
			},
		),
	)
	log.SetHandler(log15.LvlFilterHandler(log15.LvlInfo, h))
	bot.Logger = log

	line := make(chan string, 5000)
	block := make(chan struct{}, 1)
	var prevchan string
	var prevuser string
	// privmsg
	bot.AddTrigger(
		kitty.Trigger{
			Condition: func(bot *kitty.Bot, m *kitty.Message) bool {
				return m.Command == "PRIVMSG" && strings.HasPrefix(m.To, "#") && !strings.HasPrefix(m.Content, "\u0001ACTION")
			},
			Action: func(bot *kitty.Bot, m *kitty.Message) {
				block <- struct{}{}
				defer func() { <-block }()
				var msg string
				if m.To != prevchan {
					prevchan = m.To
					prevuser = m.Name
					msg = fmt.Sprintf("%s, %s says: %s", m.To, m.Name, m.Content)
					line <- msg
					return
				}
				if m.Name != prevuser {
					prevuser = m.Name
					msg = fmt.Sprintf("%s says: %s", m.Name, m.Content)
					line <- msg
					return
				}
				line <- m.Content
			},
		},
	)

	// /me action messages
	bot.AddTrigger(
		kitty.Trigger{
			Condition: func(bot *kitty.Bot, m *kitty.Message) bool {
				return m.Command == "PRIVMSG" && strings.HasPrefix(m.To, "#") && strings.HasPrefix(m.Content, "\u0001ACTION")
			},
			Action: func(bot *kitty.Bot, m *kitty.Message) {
				block <- struct{}{}
				defer func() { <-block }()
				var msg string
				if m.To != prevchan {
					prevchan = m.To
					prevuser = m.Name
					msg = fmt.Sprintf("%s, %s %s", m.To, m.Name, m.Content[8:len(m.Content)-1])
					line <- msg
					return
				}
				if m.Name != prevuser {
					prevuser = m.Name
					msg = fmt.Sprintf("%s %s", m.Name, m.Content[8:len(m.Content)-1])
					line <- msg
					return
				}
				line <- fmt.Sprintf("%s %s", m.Name, m.Content[8:len(m.Content)-1])
			},
		},
	)

	httpserver := &http.Server{
		Addr: fmt.Sprintf(":%d", STREAM_PORT),
	}
	stream := new(streamer)
	stream.init()
	http.Handle("/stream", stream)
	log.Info("stream", "url", fmt.Sprintf("http://0.0.0.0:%d/stream", STREAM_PORT))
	go func() {
		<-start
		httpserver.ListenAndServe()
	}()

	// TTS PCM generation
	go generateTTS(line)

	// push the mp3 feed
	r, w := io.Pipe()
	go generateMP3(w)
	go stream.streamMP3(r)

	for {
		bot.Run()
		time.Sleep(time.Second * 30)
	}
}

func generateTTS(line <-chan string) {
	for {
		msg := <-line
		msg = stripURLpath(msg)
		log.Debug(msg)
		piper := exec.Command(
			"piper-tts", "--output-raw", "-m",
			PIPER_TTS_VOICE,
		)
		piper.Stdin = strings.NewReader(msg)
		filename := fmt.Sprintf("%d.pcm", time.Now().UnixNano())
		f, err := os.OpenFile(filename, os.O_CREATE|os.O_RDWR, 0644)
		errExit(err)
		piper.Stdout = f
		err = piper.Run()
		errExit(err)
		err = f.Close()
		errExit(err)
		tmpdb.add(filename)
	}
}

func generateMP3(stream io.Writer) {
	ffmpeg := exec.Command("ffmpeg",
		"-f", "s16le",
		"-ar", fmt.Sprint(SPR),
		"-ac", "1",
		"-i", "-",
		"-b:a", fmt.Sprintf("%dk", BITRATE),
		"-f", "mp3",
		"-")
	ffmpeg.Stdout = stream
	r, w := io.Pipe()
	ffmpeg.Stdin = r
	err := ffmpeg.Start()
	errExit(err)

	silence := make([]byte, PCM_BUFFER)
	buf := make([]byte, PCM_BUFFER)

	var total time.Duration
	var start time.Time
	tick := func() {
		total += PCM_BUFFER_DUR
		time.Sleep(total - time.Since(start))
	}

	start = time.Now()
	for {
		file := tmpdb.get()
		if file == "" {
			tick()
			_, err := w.Write(silence)
			errExit(err)
			continue
		}

		f, err := os.Open(file)
		errExit(err)
	loop:
		for {
			n, err := f.Read(buf)
			switch err {
			case nil:
				tick()
				_, err := w.Write(append(buf[:n], silence[n:]...))
				errExit(err)
			case io.EOF:
				err = f.Close()
				errExit(err)
				err = os.Remove(file)
				errExit(err)
				break loop
			default:
				errExit(err)
			}
		}
	}
}

func (s *streamer) streamMP3(r *io.PipeReader) {
	dec := mp3.NewDecoder(r)
	frame := &mp3.Frame{}
	skipped := new(int)
	var tmp []byte
	var buflen int
	s.Lock()
	for {
		err := dec.Decode(frame, skipped)
		if err == nil {
			tmp, err = io.ReadAll(frame.Reader())
			if err == nil {
				s.buffer = append(s.buffer, tmp)
				buflen += len(tmp)
				if buflen >= INIT_BUFF {
					buflen = 0
					break
				}
			}
		}
	}
	log.Info("initial buffer built", "length", fmt.Sprintf("%ds", INIT_BUFF_SEC))
	s.Unlock()
	close(start)
	var buf [][]byte
	buflen = 0
	for {
		err := dec.Decode(frame, skipped)
		if err == nil {
			tmp, err = io.ReadAll(frame.Reader())
			if err == nil {
				buf = append(buf, tmp)
				buflen += len(tmp)
				if buflen >= WORK_BUFF {
					s.send(buf)
					buf = [][]byte{}
					buflen = 0
				}
			}
		}
	}
}

func (s *streamer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	id, recieve := s.addClient()
	defer s.delClient(id)

	// Set some headers
	w.Header().Add("Cache-Control", "no-cache, no-store, must-revalidate")
	w.Header().Add("Pragma", "no-cache")
	w.Header().Add("Expires", "0")
	w.Header().Add("Content-Type", "audio/mpeg")

	// buffered writes
	buffw := bufio.NewWriterSize(w, NETW_BUFF)

	tag := id3v2.NewEmptyTag()
	tag.SetArtist(IRC_SERVER)
	tag.SetAlbum("IRC tts service")
	tag.SetGenre("voice")
	tag.SetYear(fmt.Sprint(time.Now().Year()))
	tag.SetTitle(strings.Join(IRC_CHANNELS, " "))

	_, err := tag.WriteTo(buffw)
	if err != nil {
		return
	}

	for {
		chunk := <-recieve
		if _, err := buffw.Write(chunk); err != nil {
			return
		}
	}
}

type streamer struct {
	sync.RWMutex
	clients map[uint64]chan []byte
	id      uint64
	buffer  [][]byte
}

func (s *streamer) init() {
	s.Lock()
	defer s.Unlock()
	s.clients = make(map[uint64]chan []byte)
	s.buffer = make([][]byte, 0)
}

func (s *streamer) addClient() (id uint64, in chan []byte) {
	s.Lock()
	defer s.Unlock()
	s.id++
	s.clients[s.id] = make(chan []byte, MAX_BACKLOG/WORK_BUFF)
	s.clients[s.id] <- bytes.Join(s.buffer, nil)
	log.Info("listeners", "count", len(s.clients))
	return s.id, s.clients[s.id]
}

func (s *streamer) delClient(id uint64) {
	s.Lock()
	defer s.Unlock()
	close(s.clients[id])
	delete(s.clients, id)
	log.Info("listeners", "count", len(s.clients))
}

func (s *streamer) send(frames [][]byte) {
	s.Lock()
	buf := bytes.Join(frames, nil)
	for _, v := range s.clients {
		select {
		case v <- buf:
		default:
		}
	}
	s.buffer = append(s.buffer[len(frames):], frames...)
	s.Unlock()
}

type tmpfiles struct {
	sync.Mutex
	files []string
}

func (tmp *tmpfiles) add(name string) {
	tmp.Lock()
	tmp.files = append(tmp.files, name)
	tmp.Unlock()
}

func (tmp *tmpfiles) get() (out string) {
	tmp.Lock()
	defer tmp.Unlock()
	if len(tmp.files) > 0 {
		out = tmp.files[0]
		tmp.files = tmp.files[1:]
	}
	return
}

func newFiles() tmpfiles {
	return tmpfiles{
		files: make([]string, 0),
	}
}

var urlreg = xurls.Relaxed()

// strip URLs down to hostname
func stripURLpath(in string) string {
	matches := urlreg.FindAllString(in, -1)
	var tmp string
	for i := range matches {
		_, err := mail.ParseAddress(matches[i])
		if err == nil {
			continue
		}
		tmp = matches[i]
		if !strings.HasPrefix(tmp, "http://") && !strings.HasPrefix(tmp, "https://") {
			tmp = "https://" + tmp
		}
		link, err := url.Parse(tmp)
		if err == nil {
			in = strings.Replace(in, matches[i], link.Hostname(), -1)
		}
	}
	return in
}

func errExit(err error) {
	if err != nil {
		fmt.Fprintln(os.Stderr, "Exiting, fatal:")
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

Last edited by ugjka (2023-12-18 13:31:43)


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

Offline

#3734 2023-12-15 08:24:36

Cooleech
Member
From: Split, Croatia
Registered: 2015-01-23
Posts: 24

Re: Post your handy self made command line utilities

Simple script for displaying Caps Lock and Num Lock status in Xfce panel (useful if your keyboard doesn't have led indicators):

#!/bin/bash
PANEL=`xset -q | awk '/Caps/{print $2 $3 $4 $6 $7 $8}'`
PANEL="${PANEL//CapsLock:off/ a-z}"
PANEL="${PANEL//CapsLock:on/ A-Z}"
PANEL="${PANEL//NumLock:off/  --- }"
PANEL="${PANEL//NumLock:on/ 0-9}"
echo "<txt>$PANEL</txt>"
echo "<tool>Caps Lock and Num Lock statuses</tool>"

Save script as, say, CapsNum.sh, make it executable, add it to Generic Monitor on Xfce panel, set refresh interval to 0,5 or similar and save settings.

Offline

#3735 2023-12-15 09:15:25

seth
Member
Registered: 2012-09-03
Posts: 59,210

Re: Post your handy self made command line utilities

xset -q | awk '/Caps/{printf "%s %s", ($4=="on")?"A-Z":"a-z", ($8=="on")?"0-9":"---"}' 

Online

#3736 2023-12-15 17:26:40

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

Re: Post your handy self made command line utilities

https://github.com/ugjka/X/blob/main/dlna-send/main.go


// send a url to your dlna receiver
// Usage:
//   dlna-send [options] URL
//     -dev string
//       dlna device to use (friendly name))
//     -stop
//       stop playback

package main

import (
	"flag"
	"fmt"
	"net/url"
	"os"
	"path"
	"strconv"

	"github.com/huin/goupnp"
	"github.com/huin/goupnp/dcps/av1"
)

const USAGE = `Usage:
  %s [options] URL
    -dev string
      dlna device to use (friendly name))
    -stop
      stop playback
`

func main() {
	dev := flag.String("dev", "", "dlna device to use (friendly name))")
	stop := flag.Bool("stop", false, "stop playback")
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, USAGE, path.Base(os.Args[0]))
	}
	flag.Parse()
	var url string
	var err error
	if !*stop {
		if len(flag.Args()) > 0 {
			url = flag.Args()[0]
		} else {
			stderr(fmt.Errorf("no url given"))
		}
		err = checkURL(url)
		if err != nil {
			stderr(err)
		}
	}

	var dlna *goupnp.MaybeRootDevice
	if *dev == "" {
		dlna = chooseDLNADevice()
	} else {
		dlna, err = findDLNAreceiver(*dev)
		if err != nil {
			stderr(err)
		}
	}

	if dlna.Location != nil && !*stop {
		av1SetAndPlay(dlna.Location, url)
		return
	}

	if dlna.Location != nil && *stop {
		av1Stop(dlna.Location)
		return
	}

	stderr(fmt.Errorf("device not ready"))
}

func chooseDLNADevice() *goupnp.MaybeRootDevice {
	fmt.Println("Loading...")

	roots, err := goupnp.DiscoverDevices(av1.URN_AVTransport_1)

	fmt.Print("\033[1A\033[K")
	fmt.Println("----------")

	stderr(err)

	if len(roots) == 0 {
		stderr(fmt.Errorf("no dlna devices on the network found"))
	}
	fmt.Println("DLNA receivers")

	for i, v := range roots {
		fmt.Printf("%d: %s\n", i, v.Root.Device.FriendlyName)
	}

	fmt.Println("----------")
	fmt.Println("Select the DLNA device:")

	selected := selector(roots)
	return &roots[selected]
}

func findDLNAreceiver(friedlyName string) (*goupnp.MaybeRootDevice, error) {
	roots, err := goupnp.DiscoverDevices(av1.URN_AVTransport_1)
	if err != nil {
		return nil, err
	}
	for _, root := range roots {
		if root.Root.Device.FriendlyName == friedlyName {
			return &root, nil
		}
	}
	return nil, fmt.Errorf("'%s' not found", friedlyName)
}

func selector[slice any](s []slice) int {
	var choice int
	for {
		var choiceStr string
		_, err := fmt.Fscanln(os.Stdin, &choiceStr)
		if err != nil {
			fmt.Print("\033[1A\033[K")
			continue
		}
		choice, err = strconv.Atoi(choiceStr)
		if err != nil || choice >= len(s) {
			fmt.Print("\033[1A\033[K")
		} else {
			break
		}
	}
	fmt.Print("\033[1A\033[K")
	fmt.Printf("[%d]\n", choice)
	return choice
}

func stderr(err error) {
	if err == nil {
		return
	}
	fmt.Fprintln(os.Stderr, err)
	os.Exit(1)
}

func av1SetAndPlay(loc *url.URL, stream string) {
	client, err := av1.NewAVTransport1ClientsByURL(loc)
	stderr(err)
	err = client[0].SetAVTransportURI(0, stream, "")
	stderr(err)
	err = client[0].Play(0, "1")
	stderr(err)
}

func av1Stop(loc *url.URL) {
	client, err := av1.NewAVTransport1ClientsByURL(loc)
	if err != nil {
		return
	}
	client[0].Stop(0)
}

func checkURL(link string) error {
	parsed, err := url.Parse(link)
	if err != nil {
		return err
	}

	if parsed.Scheme == "" {
		return fmt.Errorf("no url scheme")
	}

	if parsed.Host == "" {
		return fmt.Errorf("no host")
	}
	return nil
}

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

Offline

#3737 2023-12-21 10:09:10

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

Re: Post your handy self made command line utilities

I always struggle to remember OpenRC commands so I wrote the script to simplify the service control:

Usage:

Usage: rcc <action> [service]

Actions:
   rcc start [service]    starts service
   rcc stop [service]     stops service
   rcc restart [service]  restarts service
   rcc status [service]   service status
   rcc enable [service]   enable service
   rcc disable [service]  disable service
   rcc list               shows status of all services

/usr/bin/rcc:

#!/bin/sh
set -eu

_usage() {
    _bn="$(basename "${0}")"
    printf '%s\n' "Usage: ${_bn} <action> [service]" \
                  "" \
                  "Actions:" \
                  "   ${_bn} start [service]    starts service" \
                  "   ${_bn} stop [service]     stops service" \
                  "   ${_bn} restart [service]  restarts service" \
                  "   ${_bn} status [service]   service status" \
                  "   ${_bn} enable [service]   enable service" \
                  "   ${_bn} disable [service]  disable service" \
                  "   ${_bn} list               shows status of all services"
    exit 1
}

if [ "${#}" -eq 2 ]
then
    # start
    if [ "${1}" = "start" ]
    then
        rc-service "${2}" start

    # stop
    elif [ "${1}" = "stop" ]
    then
        rc-service "${2}" stop

    # restart
    elif [ "${1}" = "restart" ]
    then
        rc-service "${2}" restart

    # status
    elif [ "${1}" = "status" ]
    then
        rc-service "${2}" status

    # enable
    elif [ "${1}" = "enable" ]
    then
        rc-update add "${2}" default

    # disable
    elif [ "${1}" = "disable" ]
    then
        rc-update del "${2}" default
    else
        _usage
    fi
elif [ "${#}" -eq 1 ]
then
    # list
    if [ "${1}" = "list" ]
    then
        rc-update -v show
    else
        _usage
    fi
else
    _usage
fi

Offline

#3738 2023-12-21 15:26:36

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

Re: Post your handy self made command line utilities

karabaja4 wrote:

I always struggle to remember OpenRC commands so I wrote the script to simplify the service control

And in doing so, you highlighted the only thing that systemd is actually good at: verb choice.

Well ... almost.  What the hell is "status".  That is surely a naming-things fail (by systemd ... given that it's the only one that is not a verb).  It could be "describe", "report", "summarize", etc.  But programmers seem to really like the word "status".

Last edited by Trilby (2023-12-21 15:33:03)


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

Offline

#3739 2023-12-25 09:36:51

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

Re: Post your handy self made command line utilities

Have a several scripts, that I wrote after reading the wiki. Hope it will work on a common setup of Archlinux. Let's start with firewall script.

Description: Setting up iptables for ipv4 and ipv6 (if exist). Ask which of ports (TCP and UDP) should to be opened (ipv4 only!), detect all ports that already used by running services and suggest them for opening. You could delete port or add some manually during execution. For setting new config you need start this script again.

Note: "Prevent SYN scan attack" commented - prevent access very aggressively when someone (even you either) want connect to host simultaneously by several services/programs, but you could try uncomment.


#!/bin/bash
#https://wiki.archlinux.org/title/Simple_stateful_firewall

#isRoot
if [ "${EUID}" -ne 0 ]; then echo "You need to run this script as root"; exit 1; fi


echo " * Flushing all rules"
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
iptables -t raw -F
iptables -t raw -X
iptables -t security -F
iptables -t security -X
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT

echo " * Setting default policies"
iptables -N TCP
iptables -N UDP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
iptables -P INPUT DROP

echo " * Allowing traffic that belongs to established connections, or new valid traffic"
iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

echo " * Allowing loopback devices"
iptables -A INPUT -i lo -j ACCEPT

echo " * Drop all traffic with an INVALID state match"
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP

echo " * Allowing ping responses"
iptables -A INPUT -p icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT

echo " * Setting TCP and UDP chains"
iptables -A INPUT -p udp -m conntrack --ctstate NEW -j UDP
iptables -A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP

#echo " * Prevent SYN scan attack for TCP"
#iptables -I TCP -p tcp -m recent --update --rsource --seconds 60 --name TCP-PORTSCAN -j REJECT --reject-with tcp-reset
#iptables -A INPUT -p tcp -m recent --set --rsource --name TCP-PORTSCAN -j REJECT --reject-with tcp-reset

#echo " * Prevent SYN scan attack for UDP"
#iptables -I UDP -p udp -m recent --update --rsource --seconds 60 --name UDP-PORTSCAN -j REJECT --reject-with icmp-port-unreachable
#iptables -A INPUT -p udp -m recent --set --rsource --name UDP-PORTSCAN -j REJECT --reject-with icmp-port-unreachable

echo " * Rejecting all other traffic"
iptables -A INPUT -j REJECT --reject-with icmp-proto-unreachable

for p in tcp udp
do
  echo
  echo "Open ${p^^} ports by processes:"
  echo
  ops=$(ss -ln --$p|grep -Ev "(127\.|\[::\])"|grep -Po '(?<=:)(\d+)'|sort -nu | tr '\n' ' ')
  ss -lnp --$p|tail --lines +2|grep -Ev "(127\.|\[::\])"|sed 's/users:(("//g;s/:/ /;s/"/ /'|awk '{print $4,$5,$7}'|(echo "Address Port Process";sort -nk3,3 -nk2)|column -t -R1
  echo
  read -rp "Please enter the ${p^^} ports (v4 only) for opening outside: " -e -i "${ops}" ops
  for op in $ops
  do
    echo " * Allowing port $op"
    iptables -A ${p^^} -p $p --dport $op -j ACCEPT
  done
  echo
done

echo " * Setting FORWARD policies"
iptables -N fw-interfaces
iptables -N fw-open
iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -j fw-interfaces
iptables -A FORWARD -j fw-open
iptables -A FORWARD -j REJECT --reject-with icmp-host-unreachable
iptables -P FORWARD DROP

echo " * SAVING RULES for iptables v4"
iptables-save -f /etc/iptables/iptables.rules

echo " * STARTING IPTABLES v4"
systemctl enable --now iptables

ipv6gateway=$(ip -6 route ls | grep default | grep -Po '(?<=via )(\S+)' | head -1)

if  [ "$ipv6gateway" != "" ]; then
  echo " * SAVING RULES for iptables v6"
  cat << EOF > /etc/iptables/ip6tables.rules
*raw
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [22:2432]
-A PREROUTING -m rpfilter -j ACCEPT
-A PREROUTING -j DROP
COMMIT
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
:TCP - [0:0]
:UDP - [0:0]
:fw-interfaces - [0:0]
:fw-open - [0:0]
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate INVALID -j DROP
-A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 128 -m conntrack --ctstate NEW -j ACCEPT
-A INPUT -s fe80::/10 -p ipv6-icmp -j ACCEPT
-A INPUT -s fd42::/10 -p ipv6-icmp -j ACCEPT
-A INPUT -p udp --sport 547 --dport 546 -j ACCEPT
-A INPUT -p udp -m conntrack --ctstate NEW -j UDP
-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j TCP
-A INPUT -p udp -j REJECT --reject-with icmp6-adm-prohibited
-A INPUT -p tcp -j REJECT --reject-with tcp-reset
-A INPUT -j REJECT --reject-with icmp6-adm-prohibited
-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -j fw-interfaces
-A FORWARD -j fw-open
-A FORWARD -j REJECT
COMMIT
EOF

  echo " * Setting ICMPv6 Neighbor Discovery Protocol"
  echo "   Default IPv6 gateway is:" $ipv6gateway
  sed -i 's/fd42::\/10/'$ipv6gateway'\/128/' /etc/iptables/ip6tables.rules

  echo " * STARTING IPTABLES v6"
  systemctl enable --now ip6tables
else
  echo " * No default IPv6 gateway found. Skip starting IPv6 iptables"
fi

echo "All set. Good luck!"

Offline

#3740 2023-12-25 10:02:46

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

Re: Post your handy self made command line utilities

Script for detecting the age of Archlinux setup:

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)"

Offline

#3741 2023-12-25 10:15:21

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

Re: Post your handy self made command line utilities

List of explicit installing packages from repositories and AUR (just more eyecandy than in the wiki):

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

Offline

#3742 2023-12-25 17:07:19

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

Re: Post your handy self made command line utilities

logger.sh - shows new events from journal when you start new bash/ssh session. Can use for ssh greatings (like motd):

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

Last edited by Nebulosa (2023-12-25 17:14:17)

Offline

#3743 2023-12-25 17:40:06

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

Re: Post your handy self made command line utilities

topmem.sh - list process descending by used memory and swap. Top 10 processes shows by default.

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

Offline

#3744 2023-12-25 18:16:05

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

Re: Post your handy self made command line utilities

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).

Last edited by Trilby (2023-12-25 18:18:41)


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

Offline

#3745 2023-12-26 08:22:25

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

Re: Post your handy self made command line utilities

Trilby wrote:

I think you mean:

TOP=${1:-10}

Good point! Didn't know about that.

Trilby wrote:

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.

Trilby wrote:

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!

Last edited by Nebulosa (2023-12-26 08:23:55)

Offline

#3746 2023-12-26 09:34:17

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

Re: Post your handy self made command line utilities

tgsay.sh - send message or some information from a bash script throught your own Telegram bot.

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

Offline

#3747 2023-12-29 22:11:49

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

Re: Post your handy self made command line utilities

Script to download RFCs and open them in lynx. Caches them to disk, so opening an RFC is instant after the first time. I have it aliased to "rfc", so I can just type "rfc (NUMBER)" to read. Assumes that there's a directory in $HOME called ".rfc-cache". Maybe it should create that directory automatically but I don't really care.

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

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

Offline

#3748 2023-12-29 22:36:42

seth
Member
Registered: 2012-09-03
Posts: 59,210

Re: Post your handy self made command line utilities

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?

Online

#3749 2023-12-29 23:25:00

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

Re: Post your handy self made command line utilities

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.

Last edited by Trilby (2023-12-29 23:27:45)


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

Offline

#3750 2023-12-29 23:44:50

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

Re: Post your handy self made command line utilities

seth wrote:

What's "test $2" for?

To see if you accidentally put a second argument. Is there a more idiomatic way to do that?

trilby wrote:

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.


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

Offline

Board footer

Powered by FluxBB