2019-09-24 09:33:23 +02:00
|
|
|
|
#!/bin/sh
|
|
|
|
|
# shellcheck source=/dev/null
|
|
|
|
|
#
|
|
|
|
|
# pfetch - Simple POSIX sh fetch script.
|
|
|
|
|
|
|
|
|
|
log() {
|
2019-09-24 11:47:47 +02:00
|
|
|
|
# The 'log()' function handles the printing of information.
|
|
|
|
|
# In 'pfetch' (and 'neofetch'!) the printing of the ascii art and info
|
|
|
|
|
# happen independently of each other.
|
|
|
|
|
#
|
|
|
|
|
# The size of the ascii art is stored and the ascii is printed first.
|
|
|
|
|
# Once the ascii is printed, the cursor is located right below the art
|
|
|
|
|
# (See marker $[1]).
|
|
|
|
|
#
|
|
|
|
|
# Using the stored ascii size, the cursor is then moved to marker $[2].
|
|
|
|
|
# This is simply a cursor up escape sequence using the "height" of the
|
|
|
|
|
# ascii art.
|
|
|
|
|
#
|
|
|
|
|
# 'log()' then moves the cursor to the right the "width" of the ascii art
|
|
|
|
|
# with an additional amount of padding to add a gap between the art and
|
|
|
|
|
# the information (See marker $[3]).
|
|
|
|
|
#
|
|
|
|
|
# When 'log()' has executed the cursor is then located at marker $[4].
|
|
|
|
|
# When 'log()' is run a second time, the next line of information is
|
|
|
|
|
# printed, moving the cursor to marker $[5].
|
|
|
|
|
#
|
|
|
|
|
# Markers $[4] and $[5] repeat all the way down through the ascii art
|
|
|
|
|
# until there is no more information left to print.
|
|
|
|
|
#
|
|
|
|
|
# Every time 'log()' is called the script keeps track of how many lines
|
|
|
|
|
# were printed. When printing is complete the cursor is then manually
|
|
|
|
|
# placed below the information and the art according to the "heights"
|
|
|
|
|
# of both.
|
|
|
|
|
#
|
|
|
|
|
# The math is simple: move cursor down $((ascii_height - info_height)).
|
|
|
|
|
# If the aim is to move the cursor from marker $[5] to marker $[6],
|
|
|
|
|
# plus the ascii height is 8 while the info height is 2 it'd be a move
|
|
|
|
|
# of 6 lines downwards.
|
|
|
|
|
#
|
|
|
|
|
# Once the cursor is at marker $[6], the script exits. This is the gist
|
|
|
|
|
# of how this "dynamic" printing and layout works.
|
|
|
|
|
#
|
2019-09-24 11:59:56 +02:00
|
|
|
|
# This method allows ascii art to be stored without markers for info
|
|
|
|
|
# and it allows for easy swapping of info order and amount.
|
2019-09-24 11:47:47 +02:00
|
|
|
|
#
|
|
|
|
|
# $[2] ___ $[3] goldie@KISS
|
|
|
|
|
# $[4](.· | $[5] os KISS Linux
|
|
|
|
|
# (<> |
|
|
|
|
|
# / __ \
|
|
|
|
|
# ( / \ /|
|
|
|
|
|
# _/\ __)/_)
|
|
|
|
|
# \/-____\/
|
|
|
|
|
# $[1]
|
|
|
|
|
#
|
|
|
|
|
# $[6] /home/goldie $
|
|
|
|
|
#
|
2019-09-24 11:29:50 +02:00
|
|
|
|
# PF_COL1: Control color of info name.
|
|
|
|
|
# PF_SEP: Control the separator between info name and info data.
|
|
|
|
|
# PF_COL2: Control color of info data.
|
2019-09-24 11:26:34 +02:00
|
|
|
|
#
|
|
|
|
|
# '\033[14C': Move cursor 14 characters to the right.
|
|
|
|
|
# TODO: Base this on ASCII art width.
|
|
|
|
|
#
|
2019-09-24 11:27:50 +02:00
|
|
|
|
# '\033[3%s': Color formatting.
|
2019-09-24 11:26:34 +02:00
|
|
|
|
# '\033[m': Reset formatting.
|
|
|
|
|
#
|
|
|
|
|
# '\033[%sD': Move cursor '${#1}' characters to the left.
|
|
|
|
|
# This allows for aligned info names and data.
|
|
|
|
|
#
|
|
|
|
|
# '\033[6C': Move cursor 6 characters to the right.
|
|
|
|
|
# This aligns the info.
|
|
|
|
|
printf '\033[14C\033[3%s;1m%s\033[m%s\033[3%sm\033[%sD\033[6C%s\033[m\n' \
|
2019-09-24 11:29:50 +02:00
|
|
|
|
"${PF_COL1:-5}" "$1" "${PF_SEP:- }" "${PF_COL2:-7}" "${#1}" "${2:-?}"
|
2019-09-24 11:01:34 +02:00
|
|
|
|
|
|
|
|
|
# Keep track of the number of times 'log()' has been run.
|
2019-09-24 12:32:06 +02:00
|
|
|
|
info_height=$((info_height + 1))
|
2019-09-24 09:33:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-24 11:59:56 +02:00
|
|
|
|
die() {
|
|
|
|
|
printf '\033[31;1merror\033[m: %s.\n' "$@" >&2
|
|
|
|
|
exit 1
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-24 10:13:40 +02:00
|
|
|
|
get_title() {
|
2019-09-24 12:34:05 +02:00
|
|
|
|
case $os in
|
2019-09-24 11:59:02 +02:00
|
|
|
|
Linux*|GNU*)
|
2019-09-24 10:13:40 +02:00
|
|
|
|
read -r hostname < /proc/sys/kernel/hostname
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
|
|
|
|
|
# Username is retrieved by first checking '$USER' with a fallback
|
|
|
|
|
# to the 'whoami' command.
|
|
|
|
|
#
|
|
|
|
|
# Hostname is retrieved by first checking '$HOSTNAME' with a fallback
|
|
|
|
|
# to the OS specific detection above and finally an additional fallback
|
|
|
|
|
# to the 'hostname' command.
|
|
|
|
|
#
|
2019-09-24 11:29:50 +02:00
|
|
|
|
# PF_SEP and PF_COL{1,2} change printing options in the 'log()' function.
|
2019-09-24 10:25:06 +02:00
|
|
|
|
#
|
|
|
|
|
# Disable the warning about '$HOSTNAME' being undefined in POSIX sh as
|
|
|
|
|
# it is intended for allowing the user to overwrite the value on invocation.
|
2019-09-24 10:13:40 +02:00
|
|
|
|
# shellcheck disable=SC2039
|
2019-09-24 11:29:50 +02:00
|
|
|
|
PF_SEP=@ PF_COL1=1 PF_COL2='3;1' \
|
2019-09-24 10:25:06 +02:00
|
|
|
|
log "${USER:-$(whoami)}" "${HOSTNAME:-${hostname:-$(hostname)}}"
|
2019-09-24 10:13:40 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-24 09:33:23 +02:00
|
|
|
|
get_distro() {
|
2019-09-24 12:34:05 +02:00
|
|
|
|
case $os in
|
2019-09-24 11:59:02 +02:00
|
|
|
|
Linux*|GNU*)
|
2019-09-24 09:33:23 +02:00
|
|
|
|
. /etc/os-release && distro=$PRETTY_NAME
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
|
2019-09-24 10:25:06 +02:00
|
|
|
|
log os "$distro"
|
2019-09-24 09:33:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-24 09:46:56 +02:00
|
|
|
|
get_kernel() {
|
2019-09-24 12:34:05 +02:00
|
|
|
|
log kernel "$kernel"
|
2019-09-24 09:46:56 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-24 12:06:41 +02:00
|
|
|
|
get_host() {
|
2019-09-24 12:34:05 +02:00
|
|
|
|
case $os in
|
2019-09-24 12:06:41 +02:00
|
|
|
|
Linux*|GNU*)
|
2019-09-24 12:40:48 +02:00
|
|
|
|
# This works by using the *last* valid file containing
|
|
|
|
|
# hardware/host information. Despite what these files are
|
|
|
|
|
# called, version doesn't always contain the version nor
|
|
|
|
|
# does name always contain the name.
|
2019-09-24 12:38:46 +02:00
|
|
|
|
read -r host < /sys/devices/virtual/dmi/id/product_name
|
|
|
|
|
read -r host < /sys/devices/virtual/dmi/id/product_version
|
|
|
|
|
read -r host < /sys/firmware/devicetree/base/model
|
2019-09-24 12:06:41 +02:00
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
|
2019-09-24 12:38:46 +02:00
|
|
|
|
log host "$host"
|
2019-09-24 12:06:41 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-24 09:46:56 +02:00
|
|
|
|
get_uptime() {
|
2019-09-24 09:53:49 +02:00
|
|
|
|
# Uptime works by retrieving the data in total seconds and then
|
|
|
|
|
# converting that data into days, hours and minutes using simple
|
|
|
|
|
# math.
|
2019-09-24 12:34:05 +02:00
|
|
|
|
case $os in
|
2019-09-24 11:59:02 +02:00
|
|
|
|
Linux*|GNU*)
|
2019-09-24 09:46:56 +02:00
|
|
|
|
IFS=. read -r s _ < /proc/uptime
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
|
2019-09-24 09:53:49 +02:00
|
|
|
|
# Convert the uptime from seconds into days, hours and minutes.
|
2019-09-24 09:46:56 +02:00
|
|
|
|
d=$((s / 60 / 60 / 24))
|
|
|
|
|
h=$((s / 60 / 60 % 24))
|
|
|
|
|
m=$((s / 60 % 60))
|
|
|
|
|
|
2019-09-24 09:53:49 +02:00
|
|
|
|
# Only append days, hours and minutes if they're non-zero.
|
2019-09-24 09:46:56 +02:00
|
|
|
|
[ "$d" = 0 ] || uptime="${uptime}${d}d "
|
|
|
|
|
[ "$h" = 0 ] || uptime="${uptime}${h}h "
|
|
|
|
|
[ "$m" = 0 ] || uptime="${uptime}${m}m "
|
|
|
|
|
|
2019-09-24 10:25:06 +02:00
|
|
|
|
log uptime "${uptime:-0m}"
|
2019-09-24 09:46:56 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-24 12:06:41 +02:00
|
|
|
|
get_packages() {
|
2019-09-24 12:23:19 +02:00
|
|
|
|
# Simple function to avoid '>/dev/null' spam.
|
|
|
|
|
# This checks to see if a command is in '$PATH'.
|
|
|
|
|
has() { command -v "$1" >/dev/null; }
|
|
|
|
|
|
|
|
|
|
# This works by first checking for which package managers are
|
|
|
|
|
# isntalled and finally by printing each package manager's
|
|
|
|
|
# package list with each package one per line.
|
|
|
|
|
#
|
|
|
|
|
# The output from this is then piped to 'wc -l' to count each
|
|
|
|
|
# line, giving us the total package count of whatever package
|
|
|
|
|
# managers are installed.
|
|
|
|
|
packages=$(
|
2019-09-24 12:34:05 +02:00
|
|
|
|
case $os in
|
2019-09-24 12:23:19 +02:00
|
|
|
|
Linux*|GNU*)
|
|
|
|
|
# Commands which print packages one per line.
|
|
|
|
|
has kiss && kiss l
|
|
|
|
|
has bonsai && bonsai list
|
|
|
|
|
has pacman-key && pacman -Qq
|
|
|
|
|
has dpkg && dpkg-query -f '.\n' -W
|
|
|
|
|
has rpm && rpm -qa
|
|
|
|
|
has xbps-query && xbps-query -l
|
|
|
|
|
has apk && apk info
|
|
|
|
|
|
|
|
|
|
# Directories containing packages.
|
|
|
|
|
has brew && printf '%s\n' "$(brew --cellar)/"*
|
|
|
|
|
has emerge && printf '%s\n' /var/db/pkg/*/*/
|
|
|
|
|
;;
|
|
|
|
|
esac | wc -l
|
|
|
|
|
)
|
2019-09-24 12:06:41 +02:00
|
|
|
|
|
|
|
|
|
log pkgs "$packages"
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-24 10:03:33 +02:00
|
|
|
|
get_memory() {
|
2019-09-24 12:34:05 +02:00
|
|
|
|
case $os in
|
2019-09-24 10:03:33 +02:00
|
|
|
|
# Used memory is calculated using the following "formula" (Linux):
|
|
|
|
|
# MemUsed = MemTotal + Shmem - MemFree - Buffers - Cached - SReclaimable
|
|
|
|
|
# Source: https://github.com/KittyKatt/screenFetch/issues/386
|
2019-09-24 11:59:02 +02:00
|
|
|
|
Linux*|GNU*)
|
2019-09-24 10:03:33 +02:00
|
|
|
|
# Parse the '/proc/meminfo' file splitting on ':' and 'k'.
|
|
|
|
|
# The format of the file is 'key: 000kB' and an additional
|
|
|
|
|
# split is used on 'k' to filter out 'kB'.
|
|
|
|
|
while IFS=:k read -r key val _; do
|
|
|
|
|
case $key in
|
|
|
|
|
MemTotal)
|
|
|
|
|
mem_used=$((mem_used + val))
|
|
|
|
|
mem_total=$val
|
|
|
|
|
;;
|
|
|
|
|
|
|
|
|
|
Shmem)
|
|
|
|
|
mem_used=$((mem_used + val))
|
|
|
|
|
;;
|
|
|
|
|
|
|
|
|
|
MemFree|Buffers|Cached|SReclaimable)
|
|
|
|
|
mem_used=$((mem_used - val))
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
done < /proc/meminfo
|
|
|
|
|
|
|
|
|
|
mem_used=$((mem_used / 1024))
|
|
|
|
|
mem_total=$((mem_total / 1024))
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
|
2019-09-24 10:25:06 +02:00
|
|
|
|
log memory "${mem_used}MiB / ${mem_total}MiB"
|
2019-09-24 10:03:33 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-24 11:01:34 +02:00
|
|
|
|
get_ascii() {
|
2019-09-24 12:34:05 +02:00
|
|
|
|
case $os in
|
2019-09-24 11:59:02 +02:00
|
|
|
|
Linux*|GNU*)
|
2019-09-24 11:01:34 +02:00
|
|
|
|
ascii="\
|
|
|
|
|
${c4} ___
|
|
|
|
|
(${c7}.· ${c4}|
|
|
|
|
|
(${c5}<> ${c4}|
|
|
|
|
|
/ ${c7}__ ${c4}\\
|
2019-09-24 11:26:34 +02:00
|
|
|
|
( ${c7}/ \\ ${c4}/|
|
2019-09-24 11:01:34 +02:00
|
|
|
|
${c5}_${c4}/\\ ${c7}__)${c4}/${c5}_${c4})
|
|
|
|
|
${c5}\/${c4}-____${c5}\/
|
|
|
|
|
"
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
|
|
|
|
|
# Store the height of the ascii art for cursor positioning.
|
|
|
|
|
# This script prints to the screen *almost* like a TUI does.
|
|
|
|
|
# It uses escape sequences to allow dynamic printing of the
|
|
|
|
|
# information through user configuration.
|
|
|
|
|
ascii_height=$(printf %s "$ascii" | wc -l)
|
|
|
|
|
|
|
|
|
|
# Print the ascii art and position the cursor back where we
|
|
|
|
|
# started prior to printing it.
|
2019-09-24 12:23:19 +02:00
|
|
|
|
# '\033[?25l': Hide the cursor.
|
|
|
|
|
# '\033[1m': Print the ascii in bold.
|
|
|
|
|
# '\033[m': Clear bold.
|
|
|
|
|
# '\033[%sA: Move the cursor up '$ascii_height' amount of lines.
|
|
|
|
|
printf '\033[?25l\033[1m%s\033[m\033[%sA' "$ascii" "$ascii_height"
|
2019-09-24 11:01:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-24 09:33:23 +02:00
|
|
|
|
main() {
|
2019-09-24 11:26:34 +02:00
|
|
|
|
# Hide 'stderr' unless the first argument is '-v'. This saves
|
|
|
|
|
# polluting the script with '2>/dev/null'.
|
|
|
|
|
[ "$1" = -v ] || exec 2>/dev/null
|
|
|
|
|
|
2019-09-24 11:01:34 +02:00
|
|
|
|
# Generic color list.
|
|
|
|
|
# Disable warning about unused variables.
|
|
|
|
|
# shellcheck disable=2034
|
|
|
|
|
{
|
2019-09-24 12:27:33 +02:00
|
|
|
|
c1='[31m'; c2='[32m'
|
|
|
|
|
c3='[33m'; c4='[34m'
|
|
|
|
|
c5='[35m'; c6='[36m'
|
|
|
|
|
c7='[37m'; c8='[38m'
|
2019-09-24 11:01:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-24 09:33:23 +02:00
|
|
|
|
# Store the output of 'uname' to avoid calling it multiple times
|
|
|
|
|
# throughout the script. 'read <<EOF' is the simplest way of reading
|
|
|
|
|
# a command into a list of variables.
|
2019-09-24 12:34:05 +02:00
|
|
|
|
read -r os kernel <<EOF
|
2019-09-24 11:01:34 +02:00
|
|
|
|
$(uname -sr)
|
2019-09-24 09:48:11 +02:00
|
|
|
|
EOF
|
2019-09-24 09:33:23 +02:00
|
|
|
|
|
2019-09-24 11:01:34 +02:00
|
|
|
|
get_ascii
|
2019-09-24 10:13:40 +02:00
|
|
|
|
get_title
|
2019-09-24 09:33:23 +02:00
|
|
|
|
get_distro
|
2019-09-24 12:06:41 +02:00
|
|
|
|
get_host
|
2019-09-24 09:46:56 +02:00
|
|
|
|
get_kernel
|
|
|
|
|
get_uptime
|
2019-09-24 12:06:41 +02:00
|
|
|
|
get_packages
|
2019-09-24 10:03:33 +02:00
|
|
|
|
get_memory
|
2019-09-24 11:01:34 +02:00
|
|
|
|
|
2019-09-24 12:32:06 +02:00
|
|
|
|
# Position the cursor below both the ascii art and information lines
|
|
|
|
|
# according to the height of both. If the information exceeds the ascii
|
|
|
|
|
# art in height, don't touch the cursor, else move it down N lines.
|
|
|
|
|
#
|
2019-09-24 11:01:34 +02:00
|
|
|
|
# 'log' contains the amount of 'get_' info lines that were printed.
|
2019-09-24 12:32:06 +02:00
|
|
|
|
#
|
|
|
|
|
# '\033[%sB': Move the cursor down N lines.
|
|
|
|
|
# '\033[?25h': Un-hide the cursor.
|
|
|
|
|
printf '\033[%sB\n\033[?25h' \
|
|
|
|
|
"$((info_height > ascii_height ? 0 : ascii_height - info_height))"
|
2019-09-24 09:33:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
main "$@"
|