Skip to content

Instantly share code, notes, and snippets.

@tkapias
Last active June 1, 2024 12:05
Show Gist options
  • Save tkapias/d66d86fe5c3c7df1470288b27559e296 to your computer and use it in GitHub Desktop.
Save tkapias/d66d86fe5c3c7df1470288b27559e296 to your computer and use it in GitHub Desktop.
lservices - colorized and searchable table of all SystemD units & unit-files - extracted functions from my .bashrc
#!/usr/bin/env bash
# sourced by bash(1) for non-login shells.
# ==============================
# FUNCTIONS
# ==============================
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# check required commands
# example: $ checkcmds "fzf eza" "$FUNCNAME"
checkcmds() {
local array=( $1 )
local start=1
local error=0
if [[ -z $2 ]]; then
local source=Your
else
local source="\'$2\'"
fi
for cmd in "${array[@]}"; do
if ! command -v $cmd 1> /dev/null; then
if [[ "$start" == "1" ]]; then
printf "\033[1;37m$source Requirements\033[0m:\n"
printf ' - %s\n' "${array[@]}"
printf '\033[1;31mErrors\033[0m:\n'
start=0
fi
printf " - '%s' not found\n" "$cmd"
local error=1
fi
done
if [[ "$error" == "1" ]]; then
return 1
fi
}
export -f checkcmds
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# pipe to skim (fuzzy search pager with preview, compatible tmux)
# or default to less or cat.
# Recommanded: skim, tmux & Nerd Fonts
# Usage: outputviewer "ENV=for-skim" "--skim=more-arguments" "skim prompte msg >" "cmd-for-preview+execute-silent" "cmd-for-execute-silent"
outputviewer() {
if command -v sk-tmux 1> /dev/null; then
$1 sk-tmux -d 75% $2 --case=smart --no-sort --layout=reverse-list --exit-0 --color=dark,bg+:237 --no-mouse --cycle --multi --ansi --tabstop=2 --header-lines=1 \
--prompt="$3" \
--preview-window="right:45%:wrap" \
--bind="ctrl-a:select-all,ctrl-d:deselect-all,ctrl-t:toggle-all,ctrl-p:toggle-preview,f1:execute-silent:($4; $5 echo)" \
--preview="printf '\n\033[1;37mKEYS: \033[1;33m󰗼\033[1;36menter/esc \033[1;33m󰱑\033[1;36mtab \033[1;33m󰜺\033[1;36mctrl-c \033[1;33m\033[1;36mctrl-a \033[1;33m\033[1;36mctrl-d \033[1;33m/\033[1;36mctrl-t \033[1;33m󱂩\033[1;36mctrl-p \033[1;33m󰐪\033[1;36mf1\n\n\033[1;37mPREVIEW:\n\033[0m\n'; $4"
elif command -v less 1> /dev/null; then
less --no-lessopen --use-color --quit-if-one-screen --ignore-case --LONG-PROMPT --RAW-CONTROL-CHARS --QUIET --no-init --chop-long-lines --tilde --mouse --header 1 --prompt "$1"
else
cat
fi
}
export -f outputviewer
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# colorized and searchable table of all SystemD units & unit-files
# per type, user or system, with a header preview.
lservices() {
Help() {
cat <<- HEREDOC
List Systemd units or c-groups.
Simplified and colorful, optional preview and fuzzy search with skim.
Syntax: lservices [-h] [-c] [-p] [-a|-d|m|P|s|S|t|T] [<username>]
Output: ServiceName UID STATE DESCRIPTION
options:
-h Print this Help.
-c Display Systemd c-groups list with systemd-cgls.
-p Disable the pager feature.
Change default listing (service,scope,socket):
-a List service related units (service,scope,socket,target,timer,slice).
-d List devices.
-m List mounts and automounts.
-P List paths.
-s List slices.
-S List swaps.
-t List targets.
-T List timers.
<username> [root] --system services using sudo,
[other] --user services using sudo,
[empty|myuser] --user for current user.
HEREDOC
}
local _LIST="service,scope,socket"
local _LISTGREP='\.service|\.scope|\.socket'
local OPTIND=0
while getopts ":hcpadmPsStT" option; do
case $option in
h) Help; return 0 ;;
c) systemd-cgls -la
return 0 ;;
p) local _NOPAGER=1;;
a) local _LIST="service,scope,socket,target,timer,slice"
local _LISTGREP='\.service|\.scope|\.socket|\.target|\.timer|\.slice';;
d) local _LIST="device"
local _LISTGREP="\.$_LIST";;
m) local _LIST="mount,automount"
local _LISTGREP='\.mount|\.automount';;
P) local _LIST="path"
local _LISTGREP="\.$_LIST";;
s) local _LIST="slice"
local _LISTGREP="\.$_LIST";;
S) local _LIST="swap"
local _LISTGREP="\.$_LIST";;
t) local _LIST="target"
local _LISTGREP="\.$_LIST";;
T) local _LIST="timer"
local _LISTGREP="\.$_LIST";;
\?) echo -e "Unknown option: -$OPTARG \n" >&2; Help; return 1;;
: ) echo -e "Missing argument for -$OPTARG \n" >&2; Help; return 1;;
* ) echo -e "Unimplemented option: -$option \n" >&2; Help; return 1;;
esac
done
shift $((OPTIND-1))
if [[ -z $1 ]]; then
local _UID=$(id -u)
else
local _UID=$(id -u $1)
fi
if [[ "$(id -u)" == "0" ]]; then
local _SUDO=""
local _SUODENV=""
else
local _SUDO="sudo"
local _SUDOENV="TMUX=$TMUX TMUX-PANE=$TMUX-PANE"
fi
if [[ "$_UID" == "0" ]]; then
checkcmds "$_SUDO systemctl grep" "$FUNCNAME" || return 1
local _SYSTEMCTL="systemctl --system"
local _LOADED=$(TERM=linux $_SUDO $_SUDOENV systemctl list-units --system -q --plain --full --no-pager -t "$_LIST" | grep -E "$_LISTGREP")
local _OTHER=$(TERM=linux $_SUDO $_SUDOENV systemctl list-unit-files --system -q --plain --full --no-pager --state disabled,indirect -t "$_LIST" | grep -E "$_LISTGREP")
elif [[ "$_UID" == "$(id -u)" ]]; then
checkcmds "systemctl grep" "$FUNCNAME" || return 1
local _SYSTEMCTL="systemctl --user"
local _SUDO=""
local _SUDOENV=""
local _LOADED=$(TERM=linux systemctl list-units --user -q --plain --full --no-pager -t "$_LIST" | grep -E "$_LISTGREP")
local _OTHER=$(TERM=linux systemctl list-unit-files --user -q --plain --full --no-pager --state disabled,indirect -t "$_LIST" | grep -E "$_LISTGREP")
else
checkcmds "$_SUDO systemctl grep" "$FUNCNAME" || return 1
local _USERNAME="$(id -u -n $_UID)"
local _SYSTEMCTL="systemctl --user -M $_USERNAME@"
local _LOADED=$(TERM=linux $_SUDO $_SUDOENV systemctl list-units --user -M $_USERNAME@ -q --plain --full --no-pager -t "$_LIST" | grep -E "$_LISTGREP")
local _OTHER=$(TERM=linux $_SUDO $_SUDOENV systemctl list-unit-files --user -M $_USERNAME@ -q --plain --full --no-pager --state disabled,indirect -t "$_LIST" | grep -E "$_LISTGREP")
fi
checkcmds "awk echo printf sort cat" "$FUNCNAME" || return 1
local _LOADED=$(echo "$_LOADED" | awk ' \
BEGIN {
red = "\033[1;31m"
green = "\033[1;32m"
yellow = "\033[1;33m"
blue = "\033[1;36m"
reset = "\033[0m"
map["running"] = green
map["start"] = green
map["listening"] = green
map["active"] = green
map["mounted"] = green
map["plugged"] = green
map["waiting"] = green
map["exited"] = yellow
map["stop"] = yellow
map["failed"] = red
map["dead"] = red
}
match($0,/^(\S+)\.([a-z]+)\s+\S+\s+\S+\s+(\S+)\s+(.*)$/,a) {
status = a[3]
if ( status in map )
$0 = reset blue a[1] "\t" a[2] reset "\t" map[status] status reset "\t" a[4]
else
$0 = reset blue a[1] "\t" a[2] reset "\t" a[3] "\t" a[4]
}
{ print } '
)
local _OTHER=$(echo "$_OTHER" | awk ' \
BEGIN {
red = "\033[1;31m"
yellow = "\033[1;33m"
blue = "\033[1;36m"
reset = "\033[0m"
map["disabled"] = red
map["indirect"] = yellow
map["enabled"] = yellow
}
match($0,/^(\S+)\.([a-z]+)\s+(\S+)\s+(\S+).*$/,a) {
status = a[3]
preset = a[4]
$0 = reset blue a[1] "\t" a[2] reset "\t" map[status] status reset "\t(preset: " map[preset] preset reset ")"
}
{ print } '
)
local _OUTPUT=$(printf "%s\n%s" "$_LOADED" "$_OTHER" | sort -f -u -t$'\t' -k 1,2)
printf "Unit\tType\tState\tComments\n%s" "$_OUTPUT" | column -s$'\t' -t \
| outputviewer \
"$_SUDO $_SUDOENV" \
"--nth=1..3 --no-hscroll" \
"Systemd states for '$_LIST' as '$(id -u -n $_UID)' > " \
"SYSTEMD_URLIFY=0 SYSTEMD_COLORS=1 $_SYSTEMCTL -q --plain --full --no-pager --output=short status -- {1}.{2} | cat" \
"echo; SYSTEMD_URLIFY=0 SYSTEMD_COLORS=1 $_SYSTEMCTL -q --plain --full --no-pager --output=short cat -- {1}.{2} | cat; echo;"
}
export -f lservices
@tkapias
Copy link
Author

tkapias commented Jun 1, 2024

Edited Revision 16:

  • More optional options for skim to disable h-scroll

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment