You are not logged in.
Oops, now I see, I need a good night rest I think..
Yeah, you're right I use a menu, my rationale was; why 'remember' if I can let the script do it for me
Offline
Systray Bluetooth Profile Switcher
https://ugjka.net
paru > yay | vesktop > discord
pacman -S spotify-launcher
mount /dev/disk/by-...
Offline
Since I'm using multiple kernel flavors but no boot manager with a visible menu, I wrote a hook to display the currently booting kernel version:
$ cat /etc/initcpio/hooks/uname
#!/usr/bin/ash
run_hook() {
echo -n " " # Align uname output with hook header.
uname -r
}
$ cat /etc/initcpio/install/uname
#!/bin/bash
build() {
add_binary "uname"
add_runscript
}
help() {
cat <<HELPEOF
This hook prints the current kernel version during the initramfs phase.
HELPEOF
}
Inofficial first vice president of the Rust Evangelism Strike Force
Offline
Not a command line script, but a Tampermonkey script for browsers to make https://m.facebook.com/ useable on desktop computer which I prefer over the new desktop design.
https://gist.github.com/ugjka/2c3a94f8a … b4d79723e9
// ==UserScript==
// @name Facebook Mobile on Desktop
// @namespace http://tampermonkey.net/
// @version 0.3
// @description Enhancments for FB mobile on Desktop!
// @author https://github.com/ugjka/
// @match https://m.facebook.com/*
// @grant none
// ==/UserScript==
(function () {
'use strict';
var body = document.getElementsByTagName("BODY")[0]
body.style.width = "500px";
body.style.margin = "auto";
document.addEventListener("DOMNodeInserted", function () {
var stories;
var composer;
try {
stories = document.getElementById("story_bucket_viewer_content").childNodes[0];
}
catch { }
if (stories) {
stories.style.width = "500px";
stories.style.margin = "auto";
};
try {
composer = document.getElementById("composer-main-view-id")
}
catch { }
if (composer) {
composer.style.width = "500px";
composer.style.margin = "auto";
};
});
})();
Last edited by ugjka (2020-12-05 18:40:19)
https://ugjka.net
paru > yay | vesktop > discord
pacman -S spotify-launcher
mount /dev/disk/by-...
Offline
I wanted to keep track of packages missing from both the Arch repos and the AUR after an update (dead packages, basically), so I wrote a script that runs anytime I use pacmatic:
#!/usr/bin/dash -
# Print out packages missing from both repos and AUR.
# shellcheck disable=SC2086
set -e
get_packages(){
curl -s https://aur.archlinux.org/packages.gz ||
printf '%s\n' "ERROR: Couldn't obtain packages." >&2
}
make_regex(){
# Output example: "^item1$|^item2$|^item3$"
printf '%s' "^$1$"
shift 1
while [ -n "$1" ]; do
printf '%s' "|^$1$"
shift 1
done
}
installed_pkgs=$(pacman -Qqm)
[ -n "$installed_pkgs" ] || exit 0
aur_packages=$(get_packages |
gzip -cd 2> /dev/null |
sort |
grep -E "($(make_regex $installed_pkgs))")
[ "$installed_pkgs" = "$aur_packages" ] ||
if [ -z "$aur_packages" ]; then
printf '%s\n' "$installed_pkgs"
else
printf '%s\n' "$installed_pkgs" |
grep -E -v "($(make_regex $aur_packages))"
fi
In other words, I probably missed some package or command that does that for me and I just overcomplicated my life yet again.
Offline
That's a lot of steps ... this should do the same:
#!/bin/sh
pacman -Qqm \
| sort > /tmp/non-repo.pkgs
curl -s https://aur.archlinux.org/packages.gz \
| zcat \
| sort \
| comm -23 /tmp/non-repo.pkgs -
Or if your shell has process substitution:
#!/bin/bash
curl -s https://aur.archlinux.org/packages.gz \
| zcat \
| sort \
| comm -23 <(pacman -Qqm | sort) -
"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman
Offline
That's a lot of steps ...
Yeah, I tend to overcomplicate things a lot. Mainly because I don't know as many commands as I should (first I've heard of both zcat and comm, for example).
Thanks for the simpler solution! I'll use the first one 'cause I understand it better (I only know how to write posix shell scripts—bash is a complete mystery to me).
Offline
zcat is usually a shellscript thar runs:
#!/bin/sh
exec gzip -cd "$@"
zless is a bit more useful of a wrapper, since it can transparently gzip -dc for you by defining $LESSOPEN, and zgrep is very useful... though mainly I'd use these convenience wrappers on disk files, not in pipelines.
P.S. If zcat is new to you, you'll probably be interested in the other convenience wrappers, the full list of which is, more or less,
pacman -Qql gzip| grep bin/z
Managing AUR repos The Right Way -- aurpublish (now a standalone tool)
Offline
zless is a bit more useful of a wrapper ...
Do you mean in general? I don't believe it'd be of any use in the present context.
... though mainly I'd use these convenience wrappers on disk files, not in pipelines.
Why is that? There's no need to save the packages.gz for this.
"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman
Offline
You're correct, I meant in the general case not for this specific script.
Disk files might be relevant any time you're inspecting general files *originating* on disk.
Managing AUR repos The Right Way -- aurpublish (now a standalone tool)
Offline
gzip also contains other utilities that are useful in general, but not specific to this use case:
gzip /usr/bin/gunzip
gzip /usr/bin/gzexe
gzip /usr/bin/gzip
gzip /usr/bin/uncompress
gzip /usr/bin/zcat
gzip /usr/bin/zcmp
gzip /usr/bin/zdiff
gzip /usr/bin/zegrep
gzip /usr/bin/zfgrep
gzip /usr/bin/zforce
gzip /usr/bin/zgrep
gzip /usr/bin/zless
gzip /usr/bin/zmore
gzip /usr/bin/znew
A dog is a man's best friend.
Offline
You could use that output lazily and paste it everywhere, of you could just...
pacx ()
{
for pkg in "$@"
do
printf "$pkg: $(pacman -Qql $pkg | grep "bin/." | sed 's/\/usr\/bin\/'// | xargs | fold -s -w $(( $(tput cols) - 2 - ${#pkg} )))\n";
done
}
I'm not satisfied with the number of pipes and it could look better with some indentation, but it does the job. Getting the thing to wrap on whitespaces only required some research. Maybe I need more awk and more printf in my life. Time for an awk week? :wacko:
EDIT:
What do you guys prefer and why? Above construct or:
for a in b; do
something
done
Last edited by Awebb (2020-12-14 08:03:18)
Offline
There is no need for everything to be nested in a subshell in the printf format string. All the commands in the subshell print to stdout anyways. More importantly: grep + sed = sed (and xargs is a confusing way to just remove newlines, which sed can do too):
for pkg in "$@"; do
printf $pkg:
pacman -Qql $pkg \
| sed -n '/bin/{s/\/usr\/bin\///;H;}${x;s/\n/ /g;p;}' \
| fold -s -w $(( $(tput cols) - 2 - ${#pkg} ))
done
And this code example should express my view on the second question.
Or to give more love to printf, it can also remove excess newlines:
for pkg in "$@"; do
printf "$pkg:"
printf " %s" $(pacman -Qql $pkg | sed -n 's/\/usr\/bin\///p}') \
| fold -s -w $(( $(tput cols) - 2 - ${#pkg} ))
printf "\n"
done
Of course none of this addresses the "fold" which has no business inside the loop. In fact, once it's out of the loop, you can ditch the gymastics dealing with the length of the pkgname:
for pkg in "$@"; do
printf "$pkg:"
printf " %s" $(pacman -Qql $pkg | sed -n 's/\/usr\/bin\///p}')
printf "\n"
done | fold -s -w $(tput cols)
Of course, as soon as you start thinking about taking things out of the loop, you may realize that there's no reason for pacman to be in the loop as pacman can act on many packages at once. So all we need to do then is get all the information from pacman in one call, then use some other process to format it. Awk is nice for this:
pacman -Ql $@ | awk '
$2 ~ "/usr/bin/" {
sub(/\/usr\/bin\//,"",$2);
pkg[$1]=pkg[$1]" "$2;
}
END {
for (p in pkg)
printf "%s:%s\n", p, pkg[p];
}
' | fold -s -w $(tput cols)
And as I love sed, it's worth showing that awk is not needed and this can also be done in sed:
pacman -Ql $@ | sed -n '
/ \/usr\/bin\/$/ {
s/ .*/:/
h
:loop
n
s/[^ ]* \/usr\/bin\///
t append
b end
:append
H
b loop
:end
x
s/\n/ /g
p
}
' | fold -s -w $(tput cols)
Or if you're a sadist, a technical oneliner:
pacman -Ql $@ | sed -n '/ \/usr\/bin\/$/{s/ .*/:/;h;:a;n;s/[^ ]* \/usr\/bin\///;tb;bc;:b;H;ba;:c;x;s/\n/ /g;p;}' | fold -s -w $(tput cols)
Last edited by Trilby (2020-12-14 14:54:34)
"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman
Offline
Thanks, Trilby. I guess that answers my EDIT question
More importantly: grep + sed = sed (and xargs is a confusing way to just remove newlines, which sed can do too):
Oh yeah, I've been abusing xargs as much as the next guy does cat for years.
Of course none of this addresses the "fold" which has no business inside the loop. In fact, once it's out of the loop, you can ditch the gymastics dealing with the length of the pkgname:
for pkg in "$@"; do printf "$pkg:" printf " %s" $(pacman -Qql $pkg | sed -n 's/\/usr\/bin\///p}') printf "\n" done | fold -s -w $(tput cols)
That's my favorite solution so far, I guess sed requires more attention. I thought I had tried exactly that fold syntax and it broke horribly.
Offline
Here's another script I use on my system, this time to send desktop notifications whenever there are packages to update (it's set on a timer for every six hours since boot). I know I can do the formatting on sed easily, but I wanted to use only shell built-in stuff for funsies.
#!/usr/bin/dash -
# Send notification on Arch/AUR updates
# shellcheck disable=SC2046
notify(){
loc="$1"
shift 1
amt="$#"
[ $amt -eq 0 ] && return 0
notify-send \
-a "acheck-$loc" \
-u normal \
-i distributor-logo-archlinux \
"$(title)" \
"$(format "${@}")"
}
title(){
case $loc in
repo )
[ $amt -eq 1 ] &&
printf '%s package updated' "$amt" ||
printf '%s packages updated' "$amt"
;;
aur )
[ $amt -eq 1 ] &&
printf '%s AUR package updated' "$amt" ||
printf '%s AUR packages updated' "$amt"
;;
esac
}
format(){
lim=$((amt < 16 ? amt : 15))
rem=$((amt - lim))
while [ $lim -ne 0 ]
do
ver="${1#* }"
printf '<b>%s</b> – %s <b>→</b> %s\n' \
"${1%% *}" \
"${ver%% *}" \
"${1##* }"
lim=$((lim - 1))
shift 1
done
[ $rem -eq 0 ] || printf '<i>...plus %s more.</i>\n' "$rem"
}
IFS="
"
notify repo $(checkupdates 2> /dev/null)
notify aur $(auracle sync 2> /dev/null)
Last edited by ephemeralCuriosities (2020-12-16 14:14:13)
Offline
Oh yeah, I've been abusing xargs as much as the next guy does cat for years.
Hello Awebb, you might want to look at this web page:
http://www.novosial.org/shell/useless-cat/
A dog is a man's best friend.
Offline
Mods are just community members who have the occasionally necessary option to move threads around and edit posts. -- Trilby
Offline
Since I did not find an appropriate existing program, I wrote a script to list imports of a python project:
#! /usr/bin/env python3
# lsimports.py - List python project imports
# Copyright (C) 2020 Richard Neumann <mail at richard dash neumann period de>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
"""Lists imports of python modules and packages."""
from argparse import ArgumentParser, Namespace
from ast import Import, ImportFrom, Module, parse
from distutils.sysconfig import get_python_lib
from itertools import chain
from logging import INFO, WARNING, basicConfig, getLogger
from pathlib import Path
from typing import Iterable, Iterator
DESCRIPTION = __doc__
LOG_FORMAT = '[%(levelname)s] %(name)s: %(message)s'
LOGGER = getLogger(Path(__file__).stem)
STDLIB = Path(get_python_lib(standard_lib=True))
def get_imports_from_module(module: Module) -> Iterator[str]:
"""Lists imports from a module AST."""
for element in module.body:
if isinstance(element, Import):
for name in element.names:
yield name.name
elif isinstance(element, ImportFrom):
yield element.module
def get_imports_from_file(path: Path) -> Iterator[str]:
"""Lists imports of the given file."""
with path.open('r') as file:
source_code = file.read()
try:
module = parse(source_code)
except SyntaxError:
LOGGER.error('Cannot parse "%s" due to syntax error.', path)
return
yield from get_imports_from_module(module)
def get_imports_from_files(paths: Iterable[Path]) -> Iterator[str]:
"""Returns the imports from multiple files."""
for path in paths:
LOGGER.info('Checking: %s', path)
yield from get_imports_from_file(path)
def get_module_root(module: str) -> str:
"""Returns a set of imported module roots."""
return module.split('.')[0]
def is_module(path: Path) -> bool:
"""Determines whether the given file is a python module."""
return path.is_file() and path.suffix == '.py'
def is_package(path: Path) -> bool:
"""Determines whether the given directory is a python package."""
if not path.is_dir():
return False
return '__init__.py' in {path.name for path in path.iterdir()}
def list_library(root: Path) -> Iterator[str]:
"""Yields modules and packages of the given library path."""
for path in root.iterdir():
if is_module(path) or is_package(path):
yield path.stem
def iterfiles(path: Path) -> Iterator[Path]:
"""Recursively yields files in a directory."""
if path.is_dir():
for subdir in path.iterdir():
yield from iterfiles(subdir)
elif path.is_file():
yield path
def get_args() -> Namespace:
"""Parses and returns the command line arguments."""
parser = ArgumentParser(description=DESCRIPTION)
parser.add_argument('path', nargs='*', type=Path, default=[Path.cwd()],
help='the files and folders to scan for imports')
parser.add_argument('-E', '--exclude-stdlib', action='store_true',
help='exclude imports from the standard library')
parser.add_argument('-e', '--exclude-modules', nargs='+', default=(),
metavar='module', help='exclude the specified modules')
parser.add_argument('-s', '--stdlib', type=Path, default=STDLIB,
metavar='path',
help='specifies the root of the standard library')
parser.add_argument('-v', '--verbose', action='store_true',
help='print verbose messages')
return parser.parse_args()
def main():
"""Runs the script."""
args = get_args()
basicConfig(format=LOG_FORMAT, level=INFO if args.verbose else WARNING)
files = filter(is_module, chain(*map(iterfiles, args.path)))
imports = set(map(get_module_root, get_imports_from_files(files)))
imports -= set(args.exclude_modules)
if args.exclude_stdlib:
imports -= set(list_library(args.stdlib))
for module in imports:
print(module)
if __name__ == '__main__':
main()
Gist: https://gist.github.com/conqp/cb4151186 … 5df431aaf3
Review: https://codereview.stackexchange.com/qu … n-projects
Last edited by schard (2020-12-24 17:20:34)
Inofficial first vice president of the Rust Evangelism Strike Force
Offline
Stumbled through the following which works for my needs to check vcs packages for available updates using `aur-srcver` and rebuild if available. The initial two lines are copied directly from aurutils code.
~ $ type vcs-sync
vcs-sync is a function
vcs-sync ()
{
AURVCSSEARCH=".*-(cvs|svn|git|hg|bzr|darcs)$";
mapfile -t mypacks < <(awk -v "mask=$AURVCSSEARCH" '$1 ~ mask {print $1}' <(aur repo --list));
declare TRIMMED_PACKS=();
AURCACHE="/pkg/aur/aurutils/sync";
if [ "${#mypacks[@]}" = 0 ]; then
printf "%s\n" "no packs here";
return 1;
else
printf "%s\n" "Checking (${#mypacks[@]}) vcs-packages for newer commits: ... ";
fi;
for i in "${!mypacks[@]}";
do
PACK="${mypacks[$i]}";
if [ -d "$AURCACHE/$PACK" ] && pacman -Q "$PACK" > /dev/null 2>&1; then
FTEST=$( (cd $AURCACHE && aur srcver "$PACK" 2>/dev/null) | awk '{print $2}');
STEST=$(pacman -Q "$PACK" | awk '{print $2}');
if [ "$(vercmp "$FTEST" "$STEST")" -gt 0 ]; then
TRIMMED_PACKS+=("${PACK}");
printf "%s\n" "$PACK has updates";
fi;
fi;
done;
if [ "${#TRIMMED_PACKS[@]}" -gt 0 ]; then
printf "%s\n" "Rebuilding (${#TRIMMED_PACKS[@]}) vcs-packages: ... " "${TRIMMED_PACKS[@]}";
( cd $AURCACHE && aur sync --rebuild "$(printf "%s\n" "${TRIMMED_PACKS[@]}")" && unset mypacks );
else
printf "%s\n" "No vcs-packages to update at this time.";
fi
}
Last edited by CarbonChauvinist (2020-12-24 16:34:35)
"the wind-blown way, wanna win? don't play"
Offline
teckk, who I think also has an account here, shared this on LQ.
Here's the Arch version:
#!/usr/bin/python
from turtle import *
from random import randint
def create_rectangle(turtle, color, x, y, width, height):
turtle.penup()
turtle.color(color)
turtle.fillcolor(color)
turtle.goto(x, y)
turtle.pendown()
turtle.begin_fill()
turtle.forward(width)
turtle.left(90)
turtle.forward(height)
turtle.left(90)
turtle.forward(width)
turtle.left(90)
turtle.forward(height)
turtle.left(90)
turtle.end_fill()
turtle.setheading(0)
def create_circle(turtle, x, y, radius, color):
oogway.penup()
oogway.color(color)
oogway.fillcolor(color)
oogway.goto(x, y)
oogway.pendown()
oogway.begin_fill()
oogway.circle(radius)
oogway.end_fill()
BG_COLOR = "#130D80"
oogway = Turtle()
oogway.speed(10)
screen = oogway.getscreen()
screen.bgcolor(BG_COLOR)
screen.title("Merry Christmas ArchLinux")
screen.setup(width=.7, height=.7)
y = -100
create_rectangle(oogway, "brown", -15, y-60, 30, 60)
width = 240
oogway.speed(20)
while width > 10:
width = width - 10
height = 10
x = 0 - width/2
create_rectangle(oogway, "green", x, y, width, height)
y = y + height
oogway.speed(5)
oogway.penup()
oogway.color('yellow')
oogway.goto(-20, y+10)
oogway.begin_fill()
oogway.pendown()
for i in range(5):
oogway.forward(40)
oogway.right(144)
oogway.end_fill()
tree_height = y + 40
create_circle(oogway, 230, 180, 60, "white")
create_circle(oogway, 220, 180, 60, BG_COLOR)
oogway.speed(20)
number_of_stars = randint(20,30)
for _ in range(0,number_of_stars):
x_star = randint(-(screen.window_width()//2),screen.window_width()//2)
y_star = randint(tree_height, screen.window_height()//2)
size = randint(5,20)
oogway.penup()
oogway.color("white")
oogway.goto(x_star, y_star)
oogway.begin_fill()
oogway.pendown()
for i in range(5):
oogway.forward(size)
oogway.right(144)
oogway.end_fill()
oogway.speed(2)
oogway.penup()
msg = ('Merry Christmas to all Archers!'
' And best wishes for a happy and healthier new year.')
oogway.goto(0, -200)
oogway.color("white")
oogway.pendown()
oogway.write(msg, move=False, align="center", font=("sans-serif", 15, "bold"))
oogway.hideturtle()
screen.mainloop()
Merry Christmas everyone!
Offline
Combined cp and progress commands into a single script to create an alias for cp to show progress while copying:
alias cp='/path/to/your/scripts/cp.sh'
#!/bin/bash
set -euo pipefail
_dep() {
if ! type "${1}" &> /dev/null
then
echo "${1} could not be found"
exit
fi
}
_dep "progress"
_dep "tput"
cp "$@" &
declare -r pid=${!}
_exit() {
kill ${pid} > /dev/null 2>&1
if (( ${?} == 0 ))
then
echo -ne "\nKilled ${pid}"
fi
}
declare ln=0
_print() {
if [[ "${1}" == "" ]]
then
return 0
fi
if (( $ln > 0 ))
then
tput cuu ${ln}
tput ed
fi
echo -e "${1}" | sed 's/^\s*//' | cut -c "-$(tput cols)"
ln=2
}
_progress() {
progress ${1:+"${1}"} -p ${pid} 2>/dev/null
}
trap "_exit" EXIT
_print "$(_progress)"
while true
do
_print "$(_progress -w)"
# die if cp finished
kill -0 "${pid}" &> /dev/null
if (( ${?} != 0 ))
then
break
fi
done
Last edited by karabaja4 (2020-12-28 06:55:58)
Offline
Entirely trivial and totally unnecessary but I was bored today stuck in the house with a bad back so I wrote this script to show a whiptail dialogue box for selecting a target partition to arch-chroot into:
#!/bin/sh
_list_part ()
{
# list all partitions except swap & those already mounted
lsblk -lno name,type,mountpoint | awk '/part/&&!/\//&&!/SWAP/{print $1,$1}'
}
_select_part ()
{
# shellcheck disable=SC2046 # word spitting is needed for the _list_part function
choice=$(whiptail --notags --menu "Please select target root partition:" 0 0 0 $(_list_part) 3>&2 2>&1 1>&3)
if [ -z "$choice" ]; then
exit 1
fi
}
_chroot ()
{
mount /dev/"$choice" /mnt
arch-chroot /mnt mount -a
arch-chroot /mnt
umount -R /mnt
}
_confirm ()
{
if whiptail --yesno "Target partition is /dev/${choice}, is this correct?" 0 0 0; then
_chroot
exit 0
fi
}
main ()
{
while true; do
_select_part
_confirm
done
}
main
@Trilby: please be gentle with me
Para todos todo, para nosotros nada
Offline
@Trilby: please be gentle with me
I wasn't going to say anything ... but with two posts in a row with it: what's with all the function names starting with underscores?
I've heard one case for such naming with the (claimed) logic that it prevents taking names in the environment that might be used for something else. This is silly logic from the start, as now multiple people are naming things starting with underscores, so name clashes will be no less likely - it's just ugly names that might clash. But far more importantly, these are scripts, not shell function libraries; the function names do not persist once the script is done running.
"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman
Offline
lsblk -lno name,type,mountpoint | awk '/part/&&!/\//&&!/SWAP/{print $1,$1}'
Dunno about whiptail, but it would probably be nice to know the label and filesystem for the selection?
(nc dialog allows to carry values different from the label for the selection)
Offline
what's with all the function names starting with underscores?
I wanted to use "chroot" as a function name so I prefixed an underscore so it wouldn't clash with the actual command. I don't actually know which would be preferred in such a situation, I suppose I really should check but I'm tired now. Anyway, once I had one function with an underscore the rest had to have them too. Obviously
it would probably be nice to know the label and filesystem for the selection?
Yes, that's a good idea. I was just focused on getting the options working — this is my first time with whiptail.
Para todos todo, para nosotros nada
Offline