├── assets └── preview.jpg ├── .editorconfig ├── Makefile ├── .github └── workflows │ └── main.yml ├── LICENSE.md ├── README.md └── pfetch /assets/preview.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unseen-ninja/pfetch/HEAD/assets/preview.jpg -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | # Force GitHub to display tabs 4 | # mixed with [4] spaces properly. 5 | [pfetch] 6 | indent_style = tab 7 | indent_size = 4 8 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PREFIX ?= /usr 2 | 3 | all: 4 | @echo RUN \'make install\' to install pfetch 5 | 6 | install: 7 | @install -Dm755 pfetch $(DESTDIR)$(PREFIX)/bin/pfetch 8 | 9 | uninstall: 10 | @rm -f $(DESTDIR)$(PREFIX)/bin/pfetch 11 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Shellcheck 2 | on: [push] 3 | jobs: 4 | build: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v1 8 | - name: Run shellcheck. 9 | run: | 10 | shellcheck pfetch 11 | TERM=dumb sh pfetch 12 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-2019 Dylan Araps 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Terminal Window showing off the Kitty ASCII art 2 |

3 |

Literally pfetch but with kitties

4 |

A pretty system information tool written in POSIX sh


5 | 6 | ## Configuration 7 | 8 | `pfetch` is configured through environment variables. 9 | 10 | ```sh 11 | # Which information to display. 12 | # NOTE: If 'ascii' will be used, it must come first. 13 | # Default: first example below 14 | # Valid: space separated string 15 | # 16 | # OFF by default: shell editor wm de palette 17 | PF_INFO="ascii title os host kernel uptime pkgs memory" 18 | 19 | # Example: Only ASCII. 20 | PF_INFO="ascii" 21 | 22 | # Example: Only Information. 23 | PF_INFO="title os host kernel uptime pkgs memory" 24 | 25 | # A file to source before running pfetch. 26 | # Default: unset 27 | # Valid: A shell script 28 | PF_SOURCE="" 29 | 30 | # Separator between info name and info data. 31 | # Default: unset 32 | # Valid: string 33 | PF_SEP=":" 34 | 35 | # Enable/Disable colors in output: 36 | # Default: 1 37 | # Valid: 1 (enabled), 0 (disabled) 38 | PF_COLOR=1 39 | 40 | # Color of info names: 41 | # Default: unset (auto) 42 | # Valid: 0-9 43 | PF_COL1=4 44 | 45 | # Color of info data: 46 | # Default: unset (auto) 47 | # Valid: 0-9 48 | PF_COL2=9 49 | 50 | # Color of title data: 51 | # Default: unset (auto) 52 | # Valid: 0-9 53 | PF_COL3=1 54 | 55 | # Alignment padding. 56 | # Default: unset (auto) 57 | # Valid: int 58 | PF_ALIGN="" 59 | 60 | # Which ascii art to use. 61 | # Default: unset (auto) 62 | # Valid: string 63 | PF_ASCII="Catppuccin" 64 | 65 | # The below environment variables control more 66 | # than just 'pfetch' and can be passed using 67 | # 'HOSTNAME=cool_pc pfetch' to restrict their 68 | # usage solely to 'pfetch'. 69 | 70 | # Which user to display. 71 | USER="" 72 | 73 | # Which hostname to display. 74 | HOSTNAME="" 75 | 76 | # Which editor to display. 77 | EDITOR="" 78 | 79 | # Which shell to display. 80 | SHELL="" 81 | 82 | # Which desktop environment to display. 83 | XDG_CURRENT_DESKTOP="" 84 | ``` 85 | 86 | ## Credit 87 | 88 | - [ufetch](https://gitlab.com/jschx/ufetch): Lots of ASCII logos. 89 | - Contrary to the belief of a certain youtuber, `pfetch` shares **zero** code with `ufetch`. Only some of the ASCII logos were used. 90 | -------------------------------------------------------------------------------- /pfetch: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # pfetch - Simple POSIX sh fetch script. 4 | 5 | # Wrapper around all escape sequences used by pfetch to allow for 6 | # greater control over which sequences are used (if any at all). 7 | esc() { 8 | case $1 in 9 | CUU) e="${esc_c}[${2}A" ;; # cursor up 10 | CUD) e="${esc_c}[${2}B" ;; # cursor down 11 | CUF) e="${esc_c}[${2}C" ;; # cursor right 12 | CUB) e="${esc_c}[${2}D" ;; # cursor left 13 | 14 | # text formatting 15 | SGR) 16 | case ${PF_COLOR:=1} in 17 | (1) 18 | e="${esc_c}[${2}m" 19 | ;; 20 | 21 | (0) 22 | # colors disabled 23 | e= 24 | ;; 25 | esac 26 | ;; 27 | 28 | # line wrap 29 | DECAWM) 30 | case $TERM in 31 | (dumb | minix | cons25) 32 | # not supported 33 | e= 34 | ;; 35 | 36 | (*) 37 | e="${esc_c}[?7${2}" 38 | ;; 39 | esac 40 | ;; 41 | esac 42 | } 43 | 44 | # Print a sequence to the terminal. 45 | esc_p() { 46 | esc "$@" 47 | printf '%s' "$e" 48 | } 49 | 50 | # This is just a simple wrapper around 'command -v' to avoid 51 | # spamming '>/dev/null' throughout this function. This also guards 52 | # against aliases and functions. 53 | has() { 54 | _cmd=$(command -v "$1") 2>/dev/null || return 1 55 | [ -x "$_cmd" ] || return 1 56 | } 57 | 58 | log() { 59 | # The 'log()' function handles the printing of information. 60 | # In 'pfetch' (and 'neofetch'!) the printing of the ascii art and info 61 | # happen independently of each other. 62 | # 63 | # The size of the ascii art is stored and the ascii is printed first. 64 | # Once the ascii is printed, the cursor is located right below the art 65 | # (See marker $[1]). 66 | # 67 | # Using the stored ascii size, the cursor is then moved to marker $[2]. 68 | # This is simply a cursor up escape sequence using the "height" of the 69 | # ascii art. 70 | # 71 | # 'log()' then moves the cursor to the right the "width" of the ascii art 72 | # with an additional amount of padding to add a gap between the art and 73 | # the information (See marker $[3]). 74 | # 75 | # When 'log()' has executed, the cursor is then located at marker $[4]. 76 | # When 'log()' is run a second time, the next line of information is 77 | # printed, moving the cursor to marker $[5]. 78 | # 79 | # Markers $[4] and $[5] repeat all the way down through the ascii art 80 | # until there is no more information left to print. 81 | # 82 | # Every time 'log()' is called the script keeps track of how many lines 83 | # were printed. When printing is complete the cursor is then manually 84 | # placed below the information and the art according to the "heights" 85 | # of both. 86 | # 87 | # The math is simple: move cursor down $((ascii_height - info_height)). 88 | # If the aim is to move the cursor from marker $[5] to marker $[6], 89 | # plus the ascii height is 8 while the info height is 2 it'd be a move 90 | # of 6 lines downwards. 91 | # 92 | # However, if the information printed is "taller" (takes up more lines) 93 | # than the ascii art, the cursor isn't moved at all! 94 | # 95 | # Once the cursor is at marker $[6], the script exits. This is the gist 96 | # of how this "dynamic" printing and layout works. 97 | # 98 | # This method allows ascii art to be stored without markers for info 99 | # and it allows for easy swapping of info order and amount. 100 | # 101 | # $[2] ___ $[3] goldie@KISS 102 | # $[4](.· | $[5] os KISS Linux 103 | # (<> | 104 | # / __ \ 105 | # ( / \ /| 106 | # _/\ __)/_) 107 | # \/-____\/ 108 | # $[1] 109 | # 110 | # $[6] /home/goldie $ 111 | 112 | # End here if no data was found. 113 | [ "$2" ] || return 114 | 115 | # Store the values of '$1' and '$3' as we reset the argument list below. 116 | name=$1 117 | use_seperator=$3 118 | 119 | # Use 'set --' as a means of stripping all leading and trailing 120 | # white-space from the info string. This also normalizes all 121 | # white-space inside of the string. 122 | # 123 | # Disable the shellcheck warning for word-splitting 124 | # as it's safe and intended ('set -f' disables globbing). 125 | # shellcheck disable=2046,2086 126 | { 127 | set -f 128 | set +f -- $2 129 | info=$* 130 | } 131 | 132 | # Move the cursor to the right, the width of the ascii art with an 133 | # additional gap for text spacing. 134 | esc_p CUF "$ascii_width" 135 | 136 | # Print the info name and color the text. 137 | esc_p SGR "3${PF_COL1-4}"; 138 | esc_p SGR 1 139 | printf '%s' "$name" 140 | esc_p SGR 0 141 | 142 | # Print the info name and info data separator, if applicable. 143 | [ "$use_seperator" ] || printf %s "$PF_SEP" 144 | 145 | # Move the cursor backward the length of the *current* info name and 146 | # then move it forwards the length of the *longest* info name. This 147 | # aligns each info data line. 148 | esc_p CUB "${#name}" 149 | esc_p CUF "${PF_ALIGN:-$info_length}" 150 | 151 | # Print the info data, color it and strip all leading whitespace 152 | # from the string. 153 | esc_p SGR "3${PF_COL2-9}" 154 | printf '%s' "$info" 155 | esc_p SGR 0 156 | printf '\n' 157 | 158 | # Keep track of the number of times 'log()' has been run. 159 | info_height=$((${info_height:-0} + 1)) 160 | } 161 | 162 | get_title() { 163 | # Username is retrieved by first checking '$USER' with a fallback 164 | # to the 'id -un' command. 165 | user=${USER:-$(id -un)} 166 | 167 | # Hostname is retrieved by first checking '$HOSTNAME' with a fallback 168 | # to the 'hostname' command. 169 | # 170 | # Disable the warning about '$HOSTNAME' being undefined in POSIX sh as 171 | # the intention for using it is allowing the user to overwrite the 172 | # value on invocation. 173 | # shellcheck disable=3028,2039 174 | hostname=${HOSTNAME:-${hostname:-$(hostname)}} 175 | 176 | # If the hostname is still not found, fallback to the contents of the 177 | # /etc/hostname file. 178 | [ "$hostname" ] || read -r hostname < /etc/hostname 179 | 180 | # Add escape sequences for coloring to user and host name. As we embed 181 | # them directly in the arguments passed to log(), we cannot use esc_p(). 182 | esc SGR 1 183 | user=$e$user 184 | esc SGR "3${PF_COL3:-1}" 185 | user=$e$user 186 | esc SGR 1 187 | user=$user$e 188 | esc SGR 1 189 | hostname=$e$hostname 190 | esc SGR "3${PF_COL3:-1}" 191 | hostname=$e$hostname 192 | 193 | log "${user}@${hostname}" " " " " >&6 194 | } 195 | 196 | get_os() { 197 | # This function is called twice, once to detect the distribution name 198 | # for the purposes of picking an ascii art early and secondly to display 199 | # the distribution name in the info output (if enabled). 200 | # 201 | # On first run, this function displays _nothing_, only on the second 202 | # invocation is 'log()' called. 203 | [ "$distro" ] && { 204 | log os "$distro" >&6 205 | return 206 | } 207 | 208 | case $os in 209 | (Linux*) 210 | # Some Linux distributions (which are based on others) 211 | # fail to identify as they **do not** change the upstream 212 | # distribution's identification packages or files. 213 | # 214 | # It is senseless to add a special case in the code for 215 | # each and every distribution (which _is_ technically no 216 | # different from what it is based on) as they're either too 217 | # lazy to modify upstream's identification files or they 218 | # don't have the know-how (or means) to ship their own 219 | # lsb-release package. 220 | # 221 | # This causes users to think there's a bug in system detection 222 | # tools like neofetch or pfetch when they technically *do* 223 | # function correctly. 224 | # 225 | # Exceptions are made for distributions which are independent, 226 | # not based on another distribution or follow different 227 | # standards. 228 | # 229 | # This applies only to distributions which follow the standard 230 | # by shipping unmodified identification files and packages 231 | # from their respective upstreams. 232 | if has lsb_release; then 233 | distro=$(lsb_release -sd) 234 | 235 | # Android detection works by checking for the existence of 236 | # the follow two directories. I don't think there's a simpler 237 | # method than this. 238 | elif [ -d /system/app ] && [ -d /system/priv-app ]; then 239 | distro="Android $(getprop ro.build.version.release)" 240 | 241 | elif [ -f /etc/os-release ]; then 242 | # This used to be a simple '. /etc/os-release' but I believe 243 | # this is insecure as we blindly executed whatever was in the 244 | # file. This parser instead simply handles 'key=val', treating 245 | # the file contents as plain-text. 246 | while IFS='=' read -r key val; do 247 | case $key in 248 | (PRETTY_NAME) 249 | distro=$val 250 | ;; 251 | esac 252 | done < /etc/os-release 253 | 254 | else 255 | # Special cases for (independent) distributions which 256 | # don't follow any os-release/lsb standards whatsoever. 257 | has crux && distro=$(crux) 258 | has guix && distro='Guix System' 259 | fi 260 | 261 | # 'os-release' and 'lsb_release' sometimes add quotes 262 | # around the distribution name, strip them. 263 | distro=${distro##[\"\']} 264 | distro=${distro%%[\"\']} 265 | 266 | # Check to see if we're running Bedrock Linux which is 267 | # very unique. This simply checks to see if the user's 268 | # PATH contains a Bedrock specific value. 269 | case $PATH in 270 | (*/bedrock/cross/*) 271 | distro='Bedrock Linux' 272 | ;; 273 | esac 274 | 275 | # Check to see if Linux is running in Windows 10 under 276 | # WSL1 (Windows subsystem for Linux [version 1]) and 277 | # append a string accordingly. 278 | # 279 | # If the kernel version string ends in "-Microsoft", 280 | # we're very likely running under Windows 10 in WSL1. 281 | if [ "$WSLENV" ]; then 282 | distro="${distro}${WSLENV+ on Windows 10 [WSL2]}" 283 | 284 | # Check to see if Linux is running in Windows 10 under 285 | # WSL2 (Windows subsystem for Linux [version 2]) and 286 | # append a string accordingly. 287 | # 288 | # This checks to see if '$WSLENV' is defined. This 289 | # appends the Windows 10 string even if '$WSLENV' is 290 | # empty. We only need to check that is has been _exported_. 291 | elif [ -z "${kernel%%*-Microsoft}" ]; then 292 | distro="$distro on Windows 10 [WSL1]" 293 | fi 294 | ;; 295 | 296 | (Darwin*) 297 | # Parse the SystemVersion.plist file to grab the macOS 298 | # version. The file is in the following format: 299 | # 300 | # ProductVersion 301 | # 10.14.6 302 | # 303 | # 'IFS' is set to '<>' to enable splitting between the 304 | # keys and a second 'read' is used to operate on the 305 | # next line directly after a match. 306 | # 307 | # '_' is used to nullify a field. '_ _ line _' basically 308 | # says "populate $line with the third field's contents". 309 | while IFS='<>' read -r _ _ line _; do 310 | case $line in 311 | # Match 'ProductVersion' and read the next line 312 | # directly as it contains the key's value. 313 | ProductVersion) 314 | IFS='<>' read -r _ _ mac_version _ 315 | continue 316 | ;; 317 | 318 | ProductName) 319 | IFS='<>' read -r _ _ mac_product _ 320 | continue 321 | ;; 322 | esac 323 | done < /System/Library/CoreServices/SystemVersion.plist 324 | 325 | # Use the ProductVersion to determine which macOS/OS X codename 326 | # the system has. As far as I'm aware there's no "dynamic" way 327 | # of grabbing this information. 328 | case $mac_version in 329 | (10.4*) distro='Mac OS X Tiger' ;; 330 | (10.5*) distro='Mac OS X Leopard' ;; 331 | (10.6*) distro='Mac OS X Snow Leopard' ;; 332 | (10.7*) distro='Mac OS X Lion' ;; 333 | (10.8*) distro='OS X Mountain Lion' ;; 334 | (10.9*) distro='OS X Mavericks' ;; 335 | (10.10*) distro='OS X Yosemite' ;; 336 | (10.11*) distro='OS X El Capitan' ;; 337 | (10.12*) distro='macOS Sierra' ;; 338 | (10.13*) distro='macOS High Sierra' ;; 339 | (10.14*) distro='macOS Mojave' ;; 340 | (10.15*) distro='macOS Catalina' ;; 341 | (11*) distro='macOS Big Sur' ;; 342 | (12*) distro='macOS Monterey' ;; 343 | (*) distro='macOS' ;; 344 | esac 345 | 346 | # Use the ProductName to determine if we're running in iOS. 347 | case $mac_product in 348 | (iP*) distro='iOS' ;; 349 | esac 350 | 351 | distro="$distro $mac_version" 352 | ;; 353 | 354 | (Haiku) 355 | # Haiku uses 'uname -v' for version information 356 | # instead of 'uname -r' which only prints '1'. 357 | distro=$(uname -sv) 358 | ;; 359 | 360 | (Minix|DragonFly) 361 | distro="$os $kernel" 362 | 363 | # Minix and DragonFly don't support the escape 364 | # sequences used, clear the exit trap. 365 | trap '' EXIT 366 | ;; 367 | 368 | (SunOS) 369 | # Grab the first line of the '/etc/release' file 370 | # discarding everything after '('. 371 | IFS='(' read -r distro _ < /etc/release 372 | ;; 373 | 374 | (OpenBSD*) 375 | # Show the OpenBSD version type (current if present). 376 | # kern.version=OpenBSD 6.6-current (GENERIC.MP) ... 377 | IFS=' =' read -r _ distro openbsd_ver _ <<-EOF 378 | $(sysctl kern.version) 379 | EOF 380 | 381 | distro="$distro $openbsd_ver" 382 | ;; 383 | 384 | (FreeBSD) 385 | distro="$os $(freebsd-version)" 386 | ;; 387 | 388 | (*) 389 | # Catch all to ensure '$distro' is never blank. 390 | # This also handles the BSDs. 391 | distro="$os $kernel" 392 | ;; 393 | esac 394 | } 395 | 396 | get_kernel() { 397 | case $os in 398 | # Don't print kernel output on some systems as the 399 | # OS name includes it. 400 | (*BSD*|Haiku|Minix) 401 | return 402 | ;; 403 | esac 404 | 405 | # '$kernel' is the cached output of 'uname -r'. 406 | log kernel "$kernel" >&6 407 | } 408 | 409 | get_host() { 410 | case $os in 411 | (Linux*) 412 | # Despite what these files are called, version doesn't 413 | # always contain the version nor does name always contain 414 | # the name. 415 | read -r name < /sys/devices/virtual/dmi/id/product_name 416 | read -r version < /sys/devices/virtual/dmi/id/product_version 417 | read -r model < /sys/firmware/devicetree/base/model 418 | 419 | host="$name $version $model" 420 | ;; 421 | 422 | (Darwin* | FreeBSD* | DragonFly*) 423 | host=$(sysctl -n hw.model) 424 | ;; 425 | 426 | (NetBSD*) 427 | host=$(sysctl -n machdep.dmi.system-vendor \ 428 | machdep.dmi.system-product) 429 | ;; 430 | 431 | (OpenBSD*) 432 | host=$(sysctl -n hw.version) 433 | ;; 434 | 435 | (*BSD* | Minix) 436 | host=$(sysctl -n hw.vendor hw.product) 437 | ;; 438 | esac 439 | 440 | # Turn the host string into an argument list so we can iterate 441 | # over it and remove OEM strings and other information which 442 | # shouldn't be displayed. 443 | # 444 | # Disable the shellcheck warning for word-splitting 445 | # as it's safe and intended ('set -f' disables globbing). 446 | # shellcheck disable=2046,2086 447 | { 448 | set -f 449 | set +f -- $host 450 | host= 451 | } 452 | 453 | # Iterate over the host string word by word as a means of stripping 454 | # unwanted and OEM information from the string as a whole. 455 | # 456 | # This could have been implemented using a long 'sed' command with 457 | # a list of word replacements, however I want to show that something 458 | # like this is possible in pure sh. 459 | # 460 | # This string reconstruction is needed as some OEMs either leave the 461 | # identification information as "To be filled by OEM", "Default", 462 | # "undefined" etc and we shouldn't print this to the screen. 463 | for word do 464 | # This works by reconstructing the string by excluding words 465 | # found in the "blacklist" below. Only non-matches are appended 466 | # to the final host string. 467 | case $word in 468 | (To | [Bb]e | [Ff]illed | [Bb]y | O.E.M. | OEM |\ 469 | Not | Applicable | Specified | System | Product | Name |\ 470 | Version | Undefined | Default | string | INVALID | � | os |\ 471 | Type1ProductConfigId ) 472 | continue 473 | ;; 474 | esac 475 | 476 | host="$host$word " 477 | done 478 | 479 | # '$arch' is the cached output from 'uname -m'. 480 | log host "${host:-$arch}" >&6 481 | } 482 | 483 | get_uptime() { 484 | # Uptime works by retrieving the data in total seconds and then 485 | # converting that data into days, hours and minutes using simple 486 | # math. 487 | case $os in 488 | (Linux* | Minix* | SerenityOS*) 489 | IFS=. read -r s _ < /proc/uptime 490 | ;; 491 | 492 | (Darwin* | *BSD* | DragonFly*) 493 | s=$(sysctl -n kern.boottime) 494 | 495 | # Extract the uptime in seconds from the following output: 496 | # [...] { sec = 1271934886, usec = 667779 } Thu Apr 22 12:14:46 2010 497 | s=${s#*=} 498 | s=${s%,*} 499 | 500 | # The uptime format from 'sysctl' needs to be subtracted from 501 | # the current time in seconds. 502 | s=$(($(date +%s) - s)) 503 | ;; 504 | 505 | (Haiku) 506 | # The boot time is returned in microseconds, convert it to 507 | # regular seconds. 508 | s=$(($(system_time) / 1000000)) 509 | ;; 510 | 511 | (SunOS) 512 | # Split the output of 'kstat' on '.' and any white-space 513 | # which exists in the command output. 514 | # 515 | # The output is as follows: 516 | # unix:0:system_misc:snaptime 14809.906993005 517 | # 518 | # The parser extracts: ^^^^^ 519 | IFS=' .' read -r _ s _ <<-EOF 520 | $(kstat -p unix:0:system_misc:snaptime) 521 | EOF 522 | ;; 523 | 524 | (IRIX) 525 | # Grab the uptime in a pretty format. Usually, 526 | # 00:00:00 from the 'ps' command. 527 | t=$(LC_ALL=POSIX ps -o etime= -p 1) 528 | 529 | # Split the pretty output into days or hours 530 | # based on the uptime. 531 | case $t in 532 | (*-*) d=${t%%-*} t=${t#*-} ;; 533 | (*:*:*) h=${t%%:*} t=${t#*:} ;; 534 | esac 535 | 536 | h=${h#0} t=${t#0} 537 | 538 | # Convert the split pretty fields back into 539 | # seconds so we may re-convert them to our format. 540 | s=$((${d:-0}*86400 + ${h:-0}*3600 + ${t%%:*}*60 + ${t#*:})) 541 | ;; 542 | esac 543 | 544 | # Convert the uptime from seconds into days, hours and minutes. 545 | d=$((s / 60 / 60 / 24)) 546 | h=$((s / 60 / 60 % 24)) 547 | m=$((s / 60 % 60)) 548 | 549 | # Only append days, hours and minutes if they're non-zero. 550 | case "$d" in ([!0]*) uptime="${uptime}${d}d "; esac 551 | case "$h" in ([!0]*) uptime="${uptime}${h}h "; esac 552 | case "$m" in ([!0]*) uptime="${uptime}${m}m "; esac 553 | 554 | log uptime "${uptime:-0m}" >&6 555 | } 556 | 557 | get_pkgs() { 558 | # This works by first checking for which package managers are 559 | # installed and finally by printing each package manager's 560 | # package list with each package one per line. 561 | # 562 | # The output from this is then piped to 'wc -l' to count each 563 | # line, giving us the total package count of whatever package 564 | # managers are installed. 565 | packages=$( 566 | case $os in 567 | (Linux*) 568 | # Commands which print packages one per line. 569 | has bonsai && bonsai list 570 | has crux && pkginfo -i 571 | has pacman-key && pacman -Qq 572 | has dpkg && dpkg-query -f '.\n' -W 573 | has rpm && rpm -qa 574 | has xbps-query && xbps-query -l 575 | has apk && apk info 576 | has guix && guix package --list-installed 577 | has opkg && opkg list-installed 578 | 579 | # Directories containing packages. 580 | has kiss && printf '%s\n' /var/db/kiss/installed/*/ 581 | has cpt-list && printf '%s\n' /var/db/cpt/installed/*/ 582 | has brew && printf '%s\n' "$(brew --cellar)/"* 583 | has emerge && printf '%s\n' /var/db/pkg/*/*/ 584 | has pkgtool && printf '%s\n' /var/log/packages/* 585 | has eopkg && printf '%s\n' /var/lib/eopkg/package/* 586 | 587 | # 'nix' requires two commands. 588 | has nix-store && { 589 | nix-store -q --requisites /run/current-system/sw 590 | nix-store -q --requisites ~/.nix-profile 591 | } 592 | ;; 593 | 594 | (Darwin*) 595 | # Commands which print packages one per line. 596 | has pkgin && pkgin list 597 | has dpkg && dpkg-query -f '.\n' -W 598 | 599 | # Directories containing packages. 600 | has brew && printf '%s\n' /usr/local/Cellar/* 601 | 602 | # 'port' prints a single line of output to 'stdout' 603 | # when no packages are installed and exits with 604 | # success causing a false-positive of 1 package 605 | # installed. 606 | # 607 | # 'port' should really exit with a non-zero code 608 | # in this case to allow scripts to cleanly handle 609 | # this behavior. 610 | has port && { 611 | pkg_list=$(port installed) 612 | 613 | case "$pkg_list" in 614 | ("No ports are installed.") 615 | # do nothing 616 | ;; 617 | 618 | (*) 619 | printf '%s\n' "$pkg_list" 620 | ;; 621 | esac 622 | } 623 | ;; 624 | 625 | (FreeBSD*|DragonFly*) 626 | pkg info 627 | ;; 628 | 629 | (OpenBSD*) 630 | printf '%s\n' /var/db/pkg/*/ 631 | ;; 632 | 633 | (NetBSD*) 634 | pkg_info 635 | ;; 636 | 637 | (Haiku) 638 | printf '%s\n' /boot/system/package-links/* 639 | ;; 640 | 641 | (Minix) 642 | printf '%s\n' /usr/pkg/var/db/pkg/*/ 643 | ;; 644 | 645 | (SunOS) 646 | has pkginfo && pkginfo -i 647 | has pkg && pkg list 648 | ;; 649 | 650 | (IRIX) 651 | versions -b 652 | ;; 653 | 654 | (SerenityOS) 655 | while IFS=" " read -r type _; do 656 | [ "$type" != dependency ] && 657 | printf "\n" 658 | done < /usr/Ports/packages.db 659 | ;; 660 | esac | wc -l 661 | ) 662 | 663 | # 'wc -l' can have leading and/or trailing whitespace 664 | # depending on the implementation, so strip them. 665 | # Procedure explained at https://github.com/dylanaraps/pure-sh-bible 666 | # (trim-leading-and-trailing-white-space-from-string) 667 | packages=${packages#"${packages%%[![:space:]]*}"} 668 | packages=${packages%"${packages##*[![:space:]]}"} 669 | 670 | case $os in 671 | # IRIX's package manager adds 3 lines of extra 672 | # output which we must account for here. 673 | (IRIX) 674 | packages=$((packages - 3)) 675 | ;; 676 | 677 | # OpenBSD's wc prints whitespace before the output 678 | # which needs to be stripped. 679 | (OpenBSD) 680 | packages=$((packages)) 681 | ;; 682 | esac 683 | 684 | case $packages in 685 | (1?*|[2-9]*) 686 | log pkgs "$packages" >&6 687 | ;; 688 | esac 689 | } 690 | 691 | get_memory() { 692 | case $os in 693 | # Used memory is calculated using the following "formula": 694 | # MemUsed = MemTotal + Shmem - MemFree - Buffers - Cached - SReclaimable 695 | # Source: https://github.com/KittyKatt/screenFetch/issues/386 696 | (Linux*) 697 | # Parse the '/proc/meminfo' file splitting on ':' and 'k'. 698 | # The format of the file is 'key: 000kB' and an additional 699 | # split is used on 'k' to filter out 'kB'. 700 | while IFS=':k ' read -r key val _; do 701 | case $key in 702 | (MemTotal) 703 | mem_used=$((mem_used + val)) 704 | mem_full=$val 705 | ;; 706 | 707 | (Shmem) 708 | mem_used=$((mem_used + val)) 709 | ;; 710 | 711 | (MemFree | Buffers | Cached | SReclaimable) 712 | mem_used=$((mem_used - val)) 713 | ;; 714 | 715 | # If detected this will be used over the above calculation 716 | # for mem_used. Available since Linux 3.14rc. 717 | # See kernel commit 34e431b0ae398fc54ea69ff85ec700722c9da773 718 | (MemAvailable) 719 | mem_avail=$val 720 | ;; 721 | esac 722 | done < /proc/meminfo 723 | 724 | case $mem_avail in 725 | (*[0-9]*) 726 | mem_used=$(((mem_full - mem_avail) / 1024)) 727 | ;; 728 | 729 | *) 730 | mem_used=$((mem_used / 1024)) 731 | ;; 732 | esac 733 | 734 | mem_full=$((mem_full / 1024)) 735 | ;; 736 | 737 | # Used memory is calculated using the following "formula": 738 | # (wired + active + occupied) * 4 / 1024 739 | (Darwin*) 740 | mem_full=$(($(sysctl -n hw.memsize) / 1024 / 1024)) 741 | 742 | # Parse the 'vmstat' file splitting on ':' and '.'. 743 | # The format of the file is 'key: 000.' and an additional 744 | # split is used on '.' to filter it out. 745 | while IFS=:. read -r key val; do 746 | case $key in 747 | (*' wired'*|*' active'*|*' occupied'*) 748 | mem_used=$((mem_used + ${val:-0})) 749 | ;; 750 | esac 751 | 752 | # Using '<<-EOF' is the only way to loop over a command's 753 | # output without the use of a pipe ('|'). 754 | # This ensures that any variables defined in the while loop 755 | # are still accessible in the script. 756 | done <<-EOF 757 | $(vm_stat) 758 | EOF 759 | 760 | mem_used=$((mem_used * 4 / 1024)) 761 | ;; 762 | 763 | (OpenBSD*) 764 | mem_full=$(($(sysctl -n hw.physmem) / 1024 / 1024)) 765 | 766 | # This is a really simpler parser for 'vmstat' which grabs 767 | # the used memory amount in a lazy way. 'vmstat' prints 3 768 | # lines of output with the needed value being stored in the 769 | # final line. 770 | # 771 | # This loop simply grabs the 3rd element of each line until 772 | # the EOF is reached. Each line overwrites the value of the 773 | # previous one so we're left with what we wanted. This isn't 774 | # slow as only 3 lines are parsed. 775 | while read -r _ _ line _; do 776 | mem_used=${line%%M} 777 | 778 | # Using '<<-EOF' is the only way to loop over a command's 779 | # output without the use of a pipe ('|'). 780 | # This ensures that any variables defined in the while loop 781 | # are still accessible in the script. 782 | done <<-EOF 783 | $(vmstat) 784 | EOF 785 | ;; 786 | 787 | # Used memory is calculated using the following "formula": 788 | # mem_full - ((inactive + free + cache) * page_size / 1024) 789 | (FreeBSD*|DragonFly*) 790 | mem_full=$(($(sysctl -n hw.physmem) / 1024 / 1024)) 791 | 792 | # Use 'set --' to store the output of the command in the 793 | # argument list. POSIX sh has no arrays but this is close enough. 794 | # 795 | # Disable the shellcheck warning for word-splitting 796 | # as it's safe and intended ('set -f' disables globbing). 797 | # shellcheck disable=2046 798 | { 799 | set -f 800 | set +f -- $(sysctl -n hw.pagesize \ 801 | vm.stats.vm.v_inactive_count \ 802 | vm.stats.vm.v_free_count \ 803 | vm.stats.vm.v_cache_count) 804 | } 805 | 806 | # Calculate the amount of used memory. 807 | # $1: hw.pagesize 808 | # $2: vm.stats.vm.v_inactive_count 809 | # $3: vm.stats.vm.v_free_count 810 | # $4: vm.stats.vm.v_cache_count 811 | mem_used=$((mem_full - (($2 + $3 + $4) * $1 / 1024 / 1024))) 812 | ;; 813 | 814 | (NetBSD*) 815 | mem_full=$(($(sysctl -n hw.physmem64) / 1024 / 1024)) 816 | 817 | # NetBSD implements a lot of the Linux '/proc' filesystem, 818 | # this uses the same parser as the Linux memory detection. 819 | while IFS=':k ' read -r key val _; do 820 | case $key in 821 | (MemFree) 822 | mem_free=$((val / 1024)) 823 | break 824 | ;; 825 | esac 826 | done < /proc/meminfo 827 | 828 | mem_used=$((mem_full - mem_free)) 829 | ;; 830 | 831 | (Haiku) 832 | # Read the first line of 'sysinfo -mem' splitting on 833 | # '(', ' ', and ')'. The needed information is then 834 | # stored in the 5th and 7th elements. Using '_' "consumes" 835 | # an element allowing us to proceed to the next one. 836 | # 837 | # The parsed format is as follows: 838 | # 3501142016 bytes free (used/max 792645632 / 4293787648) 839 | IFS='( )' read -r _ _ _ _ mem_used _ mem_full <<-EOF 840 | $(sysinfo -mem) 841 | EOF 842 | 843 | mem_used=$((mem_used / 1024 / 1024)) 844 | mem_full=$((mem_full / 1024 / 1024)) 845 | ;; 846 | 847 | (Minix) 848 | # Minix includes the '/proc' filesystem though the format 849 | # differs from Linux. The '/proc/meminfo' file is only a 850 | # single line with space separated elements and elements 851 | # 2 and 3 contain the total and free memory numbers. 852 | read -r _ mem_full mem_free _ < /proc/meminfo 853 | 854 | mem_used=$(((mem_full - mem_free) / 1024)) 855 | mem_full=$(( mem_full / 1024)) 856 | ;; 857 | 858 | (SunOS) 859 | hw_pagesize=$(pagesize) 860 | 861 | # 'kstat' outputs memory in the following format: 862 | # unix:0:system_pages:pagestotal 1046397 863 | # unix:0:system_pages:pagesfree 885018 864 | # 865 | # This simply uses the first "element" (white-space 866 | # separated) as the key and the second element as the 867 | # value. 868 | # 869 | # A variable is then assigned based on the key. 870 | while read -r key val; do 871 | case $key in 872 | (*total) 873 | pages_full=$val 874 | ;; 875 | 876 | (*free) 877 | pages_free=$val 878 | ;; 879 | esac 880 | done <<-EOF 881 | $(kstat -p unix:0:system_pages:pagestotal \ 882 | unix:0:system_pages:pagesfree) 883 | EOF 884 | 885 | mem_full=$((pages_full * hw_pagesize / 1024 / 1024)) 886 | mem_free=$((pages_free * hw_pagesize / 1024 / 1024)) 887 | mem_used=$((mem_full - mem_free)) 888 | ;; 889 | 890 | (IRIX) 891 | # Read the memory information from the 'top' command. Parse 892 | # and split each line until we reach the line starting with 893 | # "Memory". 894 | # 895 | # Example output: Memory: 160M max, 147M avail, ..... 896 | while IFS=' :' read -r label mem_full _ mem_free _; do 897 | case $label in 898 | (Memory) 899 | mem_full=${mem_full%M} 900 | mem_free=${mem_free%M} 901 | break 902 | ;; 903 | esac 904 | done <<-EOF 905 | $(top -n) 906 | EOF 907 | 908 | mem_used=$((mem_full - mem_free)) 909 | ;; 910 | 911 | (SerenityOS) 912 | IFS='{}' read -r _ memstat _ < /proc/memstat 913 | 914 | set -f -- "$IFS" 915 | IFS=, 916 | 917 | for pair in $memstat; do 918 | case $pair in 919 | (*user_physical_allocated*) 920 | mem_used=${pair##*:} 921 | ;; 922 | 923 | (*user_physical_available*) 924 | mem_free=${pair##*:} 925 | ;; 926 | esac 927 | done 928 | 929 | IFS=$1 930 | set +f -- 931 | 932 | mem_used=$((mem_used * 4096 / 1024 / 1024)) 933 | mem_free=$((mem_free * 4096 / 1024 / 1024)) 934 | 935 | mem_full=$((mem_used + mem_free)) 936 | ;; 937 | esac 938 | 939 | log memory "${mem_used:-?}M / ${mem_full:-?}M" >&6 940 | } 941 | 942 | get_wm() { 943 | case $os in 944 | (Darwin*) 945 | # Don't display window manager on macOS. 946 | ;; 947 | 948 | (*) 949 | # xprop can be used to grab the window manager's properties 950 | # which contains the window manager's name under '_NET_WM_NAME'. 951 | # 952 | # The upside to using 'xprop' is that you don't need to hardcode 953 | # a list of known window manager names. The downside is that 954 | # not all window managers conform to setting the '_NET_WM_NAME' 955 | # atom.. 956 | # 957 | # List of window managers which fail to set the name atom: 958 | # catwm, fvwm, dwm, 2bwm, monster, wmaker and sowm [mine! ;)]. 959 | # 960 | # The final downside to this approach is that it does _not_ 961 | # support Wayland environments. The only solution which supports 962 | # Wayland is the 'ps' parsing mentioned below. 963 | # 964 | # A more naive implementation is to parse the last line of 965 | # '~/.xinitrc' to extract the second white-space separated 966 | # element. 967 | # 968 | # The issue with an approach like this is that this line data 969 | # does not always equate to the name of the window manager and 970 | # could in theory be _anything_. 971 | # 972 | # This also fails when the user launches xorg through a display 973 | # manager or other means. 974 | # 975 | # 976 | # Another naive solution is to parse 'ps' with a hardcoded list 977 | # of window managers to detect the current window manager (based 978 | # on what is running). 979 | # 980 | # The issue with this approach is the need to hardcode and 981 | # maintain a list of known window managers. 982 | # 983 | # Another issue is that process names do not always equate to 984 | # the name of the window manager. False-positives can happen too. 985 | # 986 | # This is the only solution which supports Wayland based 987 | # environments sadly. It'd be nice if some kind of standard were 988 | # established to identify Wayland environments. 989 | # 990 | # pfetch's goal is to remain _simple_, if you'd like a "full" 991 | # implementation of window manager detection use 'neofetch'. 992 | # 993 | # Neofetch use a combination of 'xprop' and 'ps' parsing to 994 | # support all window managers (including non-conforming and 995 | # Wayland) though it's a lot more complicated! 996 | 997 | # Don't display window manager if X isn't running. 998 | [ "$DISPLAY" ] || return 999 | 1000 | # This is a two pass call to xprop. One call to get the window 1001 | # manager's ID and another to print its properties. 1002 | has xprop && { 1003 | # The output of the ID command is as follows: 1004 | # _NET_SUPPORTING_WM_CHECK: window id # 0x400000 1005 | # 1006 | # To extract the ID, everything before the last space 1007 | # is removed. 1008 | id=$(xprop -root -notype _NET_SUPPORTING_WM_CHECK) 1009 | id=${id##* } 1010 | 1011 | # The output of the property command is as follows: 1012 | # _NAME 8t 1013 | # _NET_WM_PID = 252 1014 | # _NET_WM_NAME = "bspwm" 1015 | # _NET_SUPPORTING_WM_CHECK: window id # 0x400000 1016 | # WM_CLASS = "wm", "Bspwm" 1017 | # 1018 | # To extract the name, everything before '_NET_WM_NAME = \"' 1019 | # is removed and everything after the next '"' is removed. 1020 | wm=$(xprop -id "$id" -notype -len 25 -f _NET_WM_NAME 8t) 1021 | } 1022 | 1023 | # Handle cases of a window manager _not_ populating the 1024 | # '_NET_WM_NAME' atom. Display nothing in this case. 1025 | case $wm in 1026 | (*'_NET_WM_NAME = '*) 1027 | wm=${wm##*_NET_WM_NAME = \"} 1028 | wm=${wm%%\"*} 1029 | ;; 1030 | 1031 | (*) 1032 | # Fallback to checking the process list 1033 | # for the select few window managers which 1034 | # don't set '_NET_WM_NAME'. 1035 | while read -r ps_line; do 1036 | case $ps_line in 1037 | (*catwm*) wm=catwm ;; 1038 | (*fvwm*) wm=fvwm ;; 1039 | (*dwm*) wm=dwm ;; 1040 | (*2bwm*) wm=2bwm ;; 1041 | (*monsterwm*) wm=monsterwm ;; 1042 | (*wmaker*) wm='Window Maker' ;; 1043 | (*sowm*) wm=sowm ;; 1044 | (*penrose*) wm=penrose ;; 1045 | esac 1046 | done <<-EOF 1047 | $(ps x) 1048 | EOF 1049 | ;; 1050 | esac 1051 | ;; 1052 | esac 1053 | 1054 | log wm "$wm" >&6 1055 | } 1056 | 1057 | 1058 | get_de() { 1059 | # This only supports Xorg related desktop environments though 1060 | # this is fine as knowing the desktop environment on Windows, 1061 | # macOS etc is useless (they'll always report the same value). 1062 | # 1063 | # Display the value of '$XDG_CURRENT_DESKTOP', if it's empty, 1064 | # display the value of '$DESKTOP_SESSION'. 1065 | log de "${XDG_CURRENT_DESKTOP:-$DESKTOP_SESSION}" >&6 1066 | } 1067 | 1068 | get_shell() { 1069 | # Display the basename of the '$SHELL' environment variable. 1070 | log shell "${SHELL##*/}" >&6 1071 | } 1072 | 1073 | get_editor() { 1074 | # Display the value of '$VISUAL', if it's empty, display the 1075 | # value of '$EDITOR'. 1076 | editor=${VISUAL:-"$EDITOR"} 1077 | 1078 | log editor "${editor##*/}" >&6 1079 | } 1080 | 1081 | get_palette() { 1082 | # Print the first 8 terminal colors. This uses the existing 1083 | # sequences to change text color with a sequence prepended 1084 | # to reverse the foreground and background colors. 1085 | # 1086 | # This allows us to save hardcoding a second set of sequences 1087 | # for background colors. 1088 | # 1089 | # False positive. 1090 | # shellcheck disable=2154 1091 | { 1092 | esc SGR 7 1093 | palette="$e$c1 $c1 $c2 $c2 $c3 $c3 $c4 $c4 $c5 $c5 $c6 $c6 " 1094 | esc SGR 0 1095 | palette="$palette$e" 1096 | } 1097 | 1098 | # Print the palette with a new-line before and afterwards but no seperator. 1099 | printf '\n' >&6 1100 | log "$palette 1101 | " " " " " >&6 1102 | } 1103 | 1104 | get_ascii() { 1105 | # This is a simple function to read the contents of 1106 | # an ascii file from 'stdin'. It allows for the use 1107 | # of '<<-EOF' to prevent the break in indentation in 1108 | # this source code. 1109 | # 1110 | # This function also sets the text colors according 1111 | # to the ascii color. 1112 | read_ascii() { 1113 | # 'PF_COL1': Set the info name color according to ascii color. 1114 | # 'PF_COL3': Set the title color to some other color. ¯\_(ツ)_/¯ 1115 | PF_COL1=${PF_COL1:-${1:-7}} 1116 | PF_COL3=${PF_COL3:-$((${1:-7}%8+1))} 1117 | 1118 | # POSIX sh has no 'var+=' so 'var=${var}append' is used. What's 1119 | # interesting is that 'var+=' _is_ supported inside '$(())' 1120 | # (arithmetic) though there's no support for 'var++/var--'. 1121 | # 1122 | # There is also no $'\n' to add a "literal"(?) newline to the 1123 | # string. The simplest workaround being to break the line inside 1124 | # the string (though this has the caveat of breaking indentation). 1125 | while IFS= read -r line; do 1126 | ascii="$ascii$line 1127 | " 1128 | done 1129 | } 1130 | 1131 | # This checks for ascii art in the following order: 1132 | # '$1': Argument given to 'get_ascii()' directly. 1133 | # '$PF_ASCII': Environment variable set by user. 1134 | # '$distro': The detected distribution name. 1135 | # '$os': The name of the operating system/kernel. 1136 | # 1137 | # NOTE: Each ascii art below is indented using tabs, this 1138 | # allows indentation to continue naturally despite 1139 | # the use of '<<-EOF'. 1140 | # 1141 | # False positive. 1142 | # shellcheck disable=2154 1143 | case ${1:-${PF_ASCII:-${distro:-$os}}} in 1144 | ([Aa]lpine*) 1145 | read_ascii 4 <<-EOF 1146 | ${c4} /\\ /\\ 1147 | /${c7}/ ${c4}\\ \\ 1148 | /${c7}/ ${c4}\\ \\ 1149 | /${c7}// ${c4}\\ \\ 1150 | ${c7}// ${c4}\\ \\ 1151 | ${c4}\\ 1152 | EOF 1153 | ;; 1154 | 1155 | ([Aa]ndroid*) 1156 | read_ascii 2 <<-EOF 1157 | ${c2} ;, ,; 1158 | ${c2} ';,.-----.,;' 1159 | ${c2} ,' ', 1160 | ${c2} / O O \\ 1161 | ${c2}| | 1162 | ${c2}'-----------------' 1163 | EOF 1164 | ;; 1165 | 1166 | ([Aa]rch*) 1167 | read_ascii 4 <<-EOF 1168 | ${c6} /\\ 1169 | ${c6} / \\ 1170 | ${c6} /\\ \\ 1171 | ${c4} / \\ 1172 | ${c4} / ,, \\ 1173 | ${c4} / | | -\\ 1174 | ${c4} /_-'' ''-_\\ 1175 | EOF 1176 | ;; 1177 | 1178 | ([Aa]rco*) 1179 | read_ascii 4 <<-EOF 1180 | ${c4} /\\ 1181 | ${c4} / \\ 1182 | ${c4} / /\\ \\ 1183 | ${c4} / / \\ \\ 1184 | ${c4} / / \\ \\ 1185 | ${c4} / / _____\\ \\ 1186 | ${c4}/_/ \`----.\\_\\ 1187 | EOF 1188 | ;; 1189 | 1190 | ([Aa]rtix*) 1191 | read_ascii 6 <<-EOF 1192 | ${c4} /\\ 1193 | ${c4} / \\ 1194 | ${c4} /\`'.,\\ 1195 | ${c4} / ', 1196 | ${c4} / ,\`\\ 1197 | ${c4} / ,.'\`. \\ 1198 | ${c4}/.,'\` \`'.\\ 1199 | EOF 1200 | ;; 1201 | 1202 | ([Bb]edrock*) 1203 | read_ascii 4 <<-EOF 1204 | ${c7}__ 1205 | ${c7}\\ \\___ 1206 | ${c7} \\ _ \\ 1207 | ${c7} \\___/ 1208 | EOF 1209 | ;; 1210 | 1211 | ([Bb]uildroot*) 1212 | read_ascii 3 <<-EOF 1213 | ${c3} ___ 1214 | ${c3} / \` \\ 1215 | ${c3}| : :| 1216 | ${c3}-. _:__.- 1217 | ${c3} \` ---- \` 1218 | EOF 1219 | ;; 1220 | 1221 | ([Cc]el[Oo][Ss]*) 1222 | read_ascii 5 0 <<-EOF 1223 | ${c5} .////\\\\\//\\. 1224 | ${c5} //_ \\\\ 1225 | ${c5} /_ ${c7}############## 1226 | ${c5} // *\\ 1227 | ${c7}############### ${c5}|# 1228 | ${c5} \/ */ 1229 | ${c5} \* ${c7}############## 1230 | ${c5} */, .// 1231 | ${c5} '_///\\\\\//_' 1232 | EOF 1233 | ;; 1234 | 1235 | ([Cc]ent[Oo][Ss]*) 1236 | read_ascii 5 <<-EOF 1237 | ${c2} ____${c3}^${c5}____ 1238 | ${c2} |\\ ${c3}|${c5} /| 1239 | ${c2} | \\ ${c3}|${c5} / | 1240 | ${c5}<---- ${c4}----> 1241 | ${c4} | / ${c2}|${c3} \\ | 1242 | ${c4} |/__${c2}|${c3}__\\| 1243 | ${c2} v 1244 | EOF 1245 | ;; 1246 | 1247 | ([Cc]rystal*[Ll]inux) 1248 | read_ascii 5 5 <<-EOF 1249 | ${c5} -//. 1250 | ${c5} -//. 1251 | ${c5} -//. . 1252 | ${c5} -//. '//- 1253 | ${c5} /+: :+/ 1254 | ${c5} .//' .//. 1255 | ${c5} . .//. 1256 | ${c5} .//. 1257 | ${c5} .//. 1258 | EOF 1259 | ;; 1260 | 1261 | ([Dd]ahlia*) 1262 | read_ascii 1 <<-EOF 1263 | ${c1} _ 1264 | ${c1} ___/ \\___ 1265 | ${c1} | _-_ | 1266 | ${c1} | / \ | 1267 | ${c1}/ | | \\ 1268 | ${c1}\\ | | / 1269 | ${c1} | \ _ _ / | 1270 | ${c1} |___ - ___| 1271 | ${c1} \\_/ 1272 | EOF 1273 | ;; 1274 | 1275 | ([Dd]ebian*) 1276 | read_ascii 1 <<-EOF 1277 | ${c1} _____ 1278 | ${c1} / __ \\ 1279 | ${c1}| / | 1280 | ${c1}| \\___- 1281 | ${c1}-_ 1282 | ${c1} --_ 1283 | EOF 1284 | ;; 1285 | 1286 | ([Dd]evuan*) 1287 | read_ascii 6 <<-EOF 1288 | ${c4} ..:::. 1289 | ${c4} ..-==- 1290 | ${c4} .+#: 1291 | ${c4} =@@ 1292 | ${c4} :+%@#: 1293 | ${c4}.:=+#@@%*: 1294 | ${c4}#@@@#=: 1295 | EOF 1296 | ;; 1297 | 1298 | ([Dd]ragon[Ff]ly*) 1299 | read_ascii 1 <<-EOF 1300 | ,${c1}_${c7}, 1301 | ('-_${c1}|${c7}_-') 1302 | >--${c1}|${c7}--< 1303 | (_-'${c1}|${c7}'-_) 1304 | ${c1}| 1305 | ${c1}| 1306 | ${c1}| 1307 | EOF 1308 | ;; 1309 | 1310 | ([Ee]lementary*) 1311 | read_ascii <<-EOF 1312 | ${c7} _______ 1313 | ${c7} / ____ \\ 1314 | ${c7}/ | / /\\ 1315 | ${c7}|__\\ / / | 1316 | ${c7}\\ /__/ / 1317 | ${c7}\\_______/ 1318 | EOF 1319 | ;; 1320 | 1321 | ([Ee]ndeavour*) 1322 | read_ascii 4 <<-EOF 1323 | ${c1}/${c4}\\ 1324 | ${c1}/${c4}/ \\${c6}\\ 1325 | ${c1}/${c4}/ \\ ${c6}\\ 1326 | ${c1}/ ${c4}/ _) ${c6}) 1327 | ${c1}/_${c4}/___-- ${c6}__- 1328 | ${c6}/____-- 1329 | EOF 1330 | ;; 1331 | 1332 | ([Ff]edora*) 1333 | read_ascii 4 <<-EOF 1334 | ${c4},'''''. 1335 | ${c4}| ,. | 1336 | ${c4}| | '_' 1337 | ${c4} ,....| |.. 1338 | ${c4}.' ,_;| ..' 1339 | ${c4}| | | | 1340 | ${c4}| ',_,' | 1341 | ${c4} '. ,' 1342 | ${c4}''''' 1343 | EOF 1344 | ;; 1345 | 1346 | ([Ff]ree[Bb][Ss][Dd]*) 1347 | read_ascii 1 <<-EOF 1348 | ${c1}/\\,-'''''-,/\\ 1349 | ${c1}\\_) (_/ 1350 | ${c1}| | 1351 | ${c1}| | 1352 | ${c1}; ; 1353 | ${c1}'-_____-' 1354 | EOF 1355 | ;; 1356 | 1357 | ([Gg]aruda*) 1358 | read_ascii 4 <<-EOF 1359 | ${c3} _______ 1360 | ${c3} __/ \\_ 1361 | ${c3} _/ / \\_ 1362 | ${c7} _/ /_________\\ 1363 | ${c7}_/ | 1364 | ${c2}\\ ____________ 1365 | ${c2} \\_ __/ 1366 | ${c2} \\__________/ 1367 | EOF 1368 | ;; 1369 | 1370 | ([Gg]entoo*) 1371 | read_ascii 5 <<-EOF 1372 | ${c5} _-----_ 1373 | ${c5}( \\ 1374 | ${c5}\\ 0 \\ 1375 | ${c7} \\ ) 1376 | ${c7} / _/ 1377 | ${c7}( _- 1378 | ${c7}\\____- 1379 | EOF 1380 | ;; 1381 | 1382 | ([Gg][Nn][Uu]*) 1383 | read_ascii 3 <<-EOF 1384 | ${c2} _-\`\`-, ,-\`\`-_ 1385 | ${c2} .' _-_| |_-_ '. 1386 | ${c2}./ /_._ _._\\ \\. 1387 | ${c2}: _/_._\`:'_._\\_ : 1388 | ${c2}\\:._/ ,\` \\ \\ \\_.:/ 1389 | ${c2} ,-';'.@) \\ @) \\ 1390 | ${c2} ,'/' ..- .\\,-.| 1391 | ${c2} /'/' \\(( \\\` ./ ) 1392 | ${c2} '/'' \\_,----' 1393 | ${c2} '/'' ,;/'' 1394 | ${c2} \`\`;' 1395 | EOF 1396 | ;; 1397 | 1398 | ([Gg]uix[Ss][Dd]*|[Gg]uix*) 1399 | read_ascii 3 <<-EOF 1400 | ${c3}|.__ __.| 1401 | ${c3}|__ \\ / __| 1402 | ${c3}\\ \\ / / 1403 | ${c3}\\ \\ / / 1404 | ${c3}\\ \\ / / 1405 | ${c3}\\ \\/ / 1406 | ${c3}\\__/ 1407 | EOF 1408 | ;; 1409 | 1410 | ([Hh]aiku*) 1411 | read_ascii 3 <<-EOF 1412 | ${c3} ,^, 1413 | ${c3} / \\ 1414 | ${c3}*--_ ; ; _--* 1415 | ${c3}\\ '" "' / 1416 | ${c3}'. .' 1417 | ${c3}.-'" "'-. 1418 | ${c3}'-.__. .__.-' 1419 | ${c3}|_| 1420 | EOF 1421 | ;; 1422 | 1423 | ([Hh]ydroOS*) 1424 | read_ascii 4 <<-EOF 1425 | ${c1}╔╗╔╗──╔╗───╔═╦══╗ 1426 | ${c1}║╚╝╠╦╦╝╠╦╦═╣║║══╣ 1427 | ${c1}║╔╗║║║╬║╔╣╬║║╠══║ 1428 | ${c1}╚╝╚╬╗╠═╩╝╚═╩═╩══╝ 1429 | ${c1}───╚═╝ 1430 | EOF 1431 | ;; 1432 | 1433 | ([Hh]yperbola*) 1434 | read_ascii <<-EOF 1435 | ${c7} |\`__.\`/ 1436 | ${c7} \____/ 1437 | ${c7} .--. 1438 | ${c7} / \\ 1439 | ${c7} / ___ \\ 1440 | ${c7}/ .\` \`.\\ 1441 | ${c7}/.\` \`.\\ 1442 | EOF 1443 | ;; 1444 | 1445 | ([Ii]glunix*) 1446 | read_ascii <<-EOF 1447 | ${c0} | 1448 | ${c0} | | 1449 | ${c0} | 1450 | ${c0} | ________ 1451 | ${c0} | /\\ | \\ 1452 | ${c0} / \\ | \\ | 1453 | ${c0} / \\ \\ | 1454 | ${c0} / \\________\\ 1455 | ${c0} \\ / / 1456 | ${c0} \\ / / 1457 | ${c0} \\ / / 1458 | ${c0} \\/________/ 1459 | EOF 1460 | ;; 1461 | 1462 | ([Ii]nstant[Oo][Ss]*) 1463 | read_ascii <<-EOF 1464 | ${c0} ,-''-, 1465 | ${c0}: .''. : 1466 | ${c0}: ',,' : 1467 | ${c0} '-____:__ 1468 | ${c0} : \`. 1469 | ${c0} \`._.' 1470 | EOF 1471 | ;; 1472 | 1473 | ([Ii][Rr][Ii][Xx]*) 1474 | read_ascii 1 <<-EOF 1475 | ${c1} __ 1476 | ${c1} \\ \\ __ 1477 | ${c1} \\ \\ / / 1478 | ${c1} \\ v / 1479 | ${c1} / . \\ 1480 | ${c1} /_/ \\ \\ 1481 | ${c1} \\_\\ 1482 | EOF 1483 | ;; 1484 | 1485 | ([Kk][Dd][Ee]*[Nn]eon*) 1486 | read_ascii 6 <<-EOF 1487 | ${c7} .${c6}__${c7}.${c6}__${c7}. 1488 | ${c6} / _${c7}.${c6}_ \\ 1489 | ${c6} / / \\ \\ 1490 | ${c7} . ${c6}| ${c7}O${c6} | ${c7}. 1491 | ${c6} \\ \\_${c7}.${c6}_/ / 1492 | ${c6} \\${c7}.${c6}__${c7}.${c6}__${c7}.${c6}/ 1493 | EOF 1494 | ;; 1495 | 1496 | ([Ll]inux*[Ll]ite*|[Ll]ite*) 1497 | read_ascii 3 <<-EOF 1498 | ${c3} /\\ 1499 | ${c3} / \\ 1500 | ${c3} / ${c7}/ ${c3}/ 1501 | ${c3}> ${c7}/ ${c3}/ 1502 | ${c3}\\ ${c7}\\ ${c3}\\ 1503 | ${c3}\\_${c7}\\${c3}_\\ 1504 | ${c7} \\ 1505 | EOF 1506 | ;; 1507 | 1508 | ([Ll]inux*[Mm]int*|[Mm]int) 1509 | read_ascii 2 <<-EOF 1510 | ${c2} ___________ 1511 | ${c2}|_ \\ 1512 | ${c2}| ${c7}| _____ ${c2}| 1513 | ${c2}| ${c7}| | | | ${c2}| 1514 | ${c2}| ${c7}| | | | ${c2}| 1515 | ${c2}| ${c7}\\__${c7}___/ ${c2}| 1516 | ${c2}\\_________/ 1517 | EOF 1518 | ;; 1519 | 1520 | 1521 | ([Ll]inux*) 1522 | read_ascii 4 <<-EOF 1523 | ${c4} ___ 1524 | ${c4}(${c7}.. ${c4}| 1525 | ${c4}(${c5}<> ${c4}| 1526 | ${c4}/ ${c7}__ ${c4}\\ 1527 | ${c4}( ${c7}/ \\ ${c4}/| 1528 | ${c5}_${c4}/\\ ${c7}__)${c4}/${c5}_${c4}) 1529 | ${c5}\/${c4}-____${c5}\/ 1530 | EOF 1531 | ;; 1532 | 1533 | ([Mm]ac[Oo][Ss]*|[Dd]arwin*) 1534 | read_ascii 1 <<-EOF 1535 | ${c2} .:' 1536 | ${c2} _ :'_ 1537 | ${c3} .'\`_\`-'_\`\`. 1538 | ${c1}:________.-' 1539 | ${c1}:_______: 1540 | ${c4} :_______\`-; 1541 | ${c5} \`._.-._.' 1542 | EOF 1543 | ;; 1544 | 1545 | ([Mm]ageia*) 1546 | read_ascii 2 <<-EOF 1547 | ${c6} * 1548 | ${c6} * 1549 | ${c6} ** 1550 | ${c7} /\\__/\\ 1551 | ${c7}/ \\ 1552 | ${c7}\\ / 1553 | ${c7} \\____/ 1554 | EOF 1555 | ;; 1556 | 1557 | ([Mm]anjaro*) 1558 | read_ascii 2 <<-EOF 1559 | ${c2}||||||||| |||| 1560 | ${c2}||||||||| |||| 1561 | ${c2}|||| |||| 1562 | ${c2}|||| |||| |||| 1563 | ${c2}|||| |||| |||| 1564 | ${c2}|||| |||| |||| 1565 | ${c2}|||| |||| |||| 1566 | EOF 1567 | ;; 1568 | 1569 | ([Mm]inix*) 1570 | read_ascii 4 <<-EOF 1571 | ${c4} ,, ,, 1572 | ${c4};${c7},${c4} ', ,' ${c7},${c4}; 1573 | ${c4}; ${c7}',${c4} ',,' ${c7},'${c4} ; 1574 | ${c4}; ${c7}',${c4} ${c7},'${c4} ; 1575 | ${c4}; ${c7};, '' ,;${c4} ; 1576 | ${c4}; ${c7};${c4};${c7}',,'${c4};${c7};${c4} ; 1577 | ${c4}', ${c7};${c4};; ;;${c7};${c4} ,' 1578 | ${c4} '${c7};${c4}' '${c7};${c4}' 1579 | EOF 1580 | ;; 1581 | 1582 | ([Mm][Xx]*) 1583 | read_ascii <<-EOF 1584 | ${c7} \\\\ / 1585 | ${c7} \\\\/ 1586 | ${c7} \\\\ 1587 | ${c7} /\\/ \\\\ 1588 | ${c7} / \\ /\\ 1589 | ${c7} / \\/ \\ 1590 | ${c7}/__________\\ 1591 | EOF 1592 | ;; 1593 | 1594 | ([Nn]et[Bb][Ss][Dd]*) 1595 | read_ascii 3 <<-EOF 1596 | ${c7}\\\\${c3}\`-______,----__ 1597 | ${c7} \\\\ ${c3}__,---\`_ 1598 | ${c7} \\\\ ${c3}\`.____ 1599 | ${c7} \\\\${c3}-______,----\`- 1600 | ${c7} \\\\ 1601 | ${c7} \\\\ 1602 | ${c7} \\\\ 1603 | EOF 1604 | ;; 1605 | 1606 | ([Nn]ix[Oo][Ss]*) 1607 | read_ascii 4 <<-EOF 1608 | ${c4} \\\\ \\\\ // 1609 | ${c4} ==\\\\__\\\\/ // 1610 | ${c4} // \\\\// 1611 | ${c4}==// //== 1612 | ${c4} //\\\\___// 1613 | ${c4}// /\\\\ \\\\== 1614 | ${c4} // \\\\ \\\\ 1615 | EOF 1616 | ;; 1617 | 1618 | ([Oo]pen[Bb][Ss][Dd]*) 1619 | read_ascii 3 <<-EOF 1620 | ${c3} _____ 1621 | ${c3} \\- -/ 1622 | ${c3} \\_/ \\ 1623 | ${c3} | ${c7}O O${c3} | 1624 | ${c3} |_ < ) 3 ) 1625 | ${c3} / \\ / 1626 | ${c3} /-_____-\\ 1627 | EOF 1628 | ;; 1629 | 1630 | ([Oo]pen[Ss][Uu][Ss][Ee]*[Tt]umbleweed*) 1631 | read_ascii 2 <<-EOF 1632 | ${c2} _____ ______ 1633 | ${c2} / ____\\ / ____ \\ 1634 | ${c2}/ / \`/ / \\ \\ 1635 | ${c2}\\ \\____/ /,____/ / 1636 | ${c2} \\______/ \\_____/ 1637 | EOF 1638 | ;; 1639 | 1640 | ([Oo]pen[Ss][Uu][Ss][Ee]*|[Oo]pen*SUSE*|SUSE*|suse*) 1641 | read_ascii 2 <<-EOF 1642 | ${c2} _______ 1643 | ${c2}__| __ \\ 1644 | ${c2} / .\\ \\ 1645 | ${c2} \\__/ | 1646 | ${c2} _______| 1647 | ${c2} \\_______ 1648 | ${c2}__________/ 1649 | EOF 1650 | ;; 1651 | 1652 | ([Oo]pen[Ww]rt*) 1653 | read_ascii 1 <<-EOF 1654 | ${c1} _______ 1655 | ${c1}| |.-----.-----.-----. 1656 | ${c1}| - || _ | -__| | 1657 | ${c1}|_______|| __|_____|__|__| 1658 | ${c1} ________|__| __ 1659 | ${c1}| | | |.----.| |_ 1660 | ${c1}| | | || _|| _| 1661 | ${c1}|________||__| |____| 1662 | EOF 1663 | ;; 1664 | 1665 | ([Pp]arabola*) 1666 | read_ascii 5 <<-EOF 1667 | ${c5} __ __ __ _ 1668 | ${c5}.\`_//_//_/ / \`. 1669 | ${c5} / .\` 1670 | ${c5} / .\` 1671 | ${c5} /.\` 1672 | ${c5} /\` 1673 | EOF 1674 | ;; 1675 | 1676 | ([Pp]op!_[Oo][Ss]*) 1677 | read_ascii 6 <<-EOF 1678 | ${c6}______ 1679 | ${c6}\\ _ \\ __ 1680 | ${c6}\\ \\ \\ \\ / / 1681 | ${c6}\\ \\_\\ \\ / / 1682 | ${c6}\\ ___\\ /_/ 1683 | ${c6} \\ \\ _ 1684 | ${c6} __\\_\\__(_)_ 1685 | ${c6}(___________) 1686 | EOF 1687 | ;; 1688 | 1689 | ([Pp]ure[Oo][Ss]*) 1690 | read_ascii <<-EOF 1691 | ${c7} _____________ 1692 | ${c7}| _________ | 1693 | ${c7}| | | | 1694 | ${c7}| | | | 1695 | ${c7}| |_________| | 1696 | ${c7}|_____________| 1697 | EOF 1698 | ;; 1699 | 1700 | ([Rr]aspbian*) 1701 | read_ascii 1 <<-EOF 1702 | ${c2} __ __ 1703 | ${c2} (_\\)(/_) 1704 | ${c1} (_(__)_) 1705 | ${c1}(_(_)(_)_) 1706 | ${c1} (_(__)_) 1707 | ${c1} (__) 1708 | EOF 1709 | ;; 1710 | 1711 | ([Ss]erenity[Oo][Ss]*) 1712 | read_ascii 4 <<-EOF 1713 | ${c7} _____ 1714 | ${c1} ,-${c7} -, 1715 | ${c1} ;${c7} ( ; 1716 | ${c1}| ${c7}. \_${c1}.,${c7} | 1717 | ${c1}| ${c7}o _${c1} ',${c7} | 1718 | ${c1} ; ${c7}(_)${c1} )${c7} ; 1719 | ${c1} '-_____-${c7}' 1720 | EOF 1721 | ;; 1722 | 1723 | ([Ss]lackware*) 1724 | read_ascii 4 <<-EOF 1725 | ${c4} ________ 1726 | ${c4} / ______| 1727 | ${c4} | |______ 1728 | ${c4} \\______ \\ 1729 | ${c4} ______| | 1730 | ${c4}| |________/ 1731 | ${c4}|____________ 1732 | EOF 1733 | ;; 1734 | 1735 | ([Ss]olus*) 1736 | read_ascii 4 <<-EOF 1737 | ${c6} 1738 | ${c6} /| 1739 | ${c6} / |\\ 1740 | ${c6} / | \\ _ 1741 | ${c6} /___|__\\_\\ 1742 | ${c6} \\ / 1743 | ${c6} \`-------´ 1744 | EOF 1745 | ;; 1746 | 1747 | ([Ss]un[Oo][Ss]|[Ss]olaris*) 1748 | read_ascii 3 <<-EOF 1749 | ${c3} . .; . 1750 | ${c3} . :; :: ;: . 1751 | ${c3} .;. .. .. .;. 1752 | ${c3}.. .. .. .. 1753 | ${c3} .;, ,;. 1754 | EOF 1755 | ;; 1756 | 1757 | ([Uu]buntu*) 1758 | read_ascii 3 <<-EOF 1759 | ${c3} _ 1760 | ${c3} ---(_) 1761 | ${c3} _/ --- \\ 1762 | ${c3}(_) | | 1763 | ${c3} \\ --- _/ 1764 | ${c3} ---(_) 1765 | EOF 1766 | ;; 1767 | 1768 | ([Vv]oid*) 1769 | read_ascii 2 <<-EOF 1770 | ${c2} _______ 1771 | ${c2} _ \\______ - 1772 | ${c2}| \\ ___ \\ | 1773 | ${c2}| | / \ | | 1774 | ${c2}| | \___/ | | 1775 | ${c2}| \\______ \\_| 1776 | ${c2} -_______\\ 1777 | EOF 1778 | ;; 1779 | 1780 | ([Xx]eonix*) 1781 | read_ascii 2 <<-EOF 1782 | ${c2} ___ ___ 1783 | ${c2}___ \ \/ / ___ 1784 | ${c2}\ \ \ / / / 1785 | ${c2} \ \/ \/ / 1786 | ${c2} \ /\ / 1787 | ${c2} \__/ \__/ 1788 | EOF 1789 | ;; 1790 | 1791 | ([Cc]atppuccin*) 1792 | read_ascii 2 <<-EOF 1793 | ${c2} /| 、 1794 | ${c2}(°、 。 7 1795 | ${c2} |、 ~ヽ 1796 | ${c2} じしf_,)〳‎‎ 1797 | EOF 1798 | ;; 1799 | 1800 | 1801 | (*) 1802 | # On no match of a distribution ascii art, this function calls 1803 | # itself again, this time to look for a more generic OS related 1804 | # ascii art (KISS Linux -> Linux). 1805 | [ "$1" ] || { 1806 | get_ascii "$os" 1807 | return 1808 | } 1809 | 1810 | printf 'error: %s is not currently supported.\n' "$os" >&6 1811 | printf 'error: Open an issue for support to be added.\n' >&6 1812 | exit 1 1813 | ;; 1814 | esac 1815 | 1816 | # Store the "width" (longest line) and "height" (number of lines) 1817 | # of the ascii art for positioning. This script prints to the screen 1818 | # *almost* like a TUI does. It uses escape sequences to allow dynamic 1819 | # printing of the information through user configuration. 1820 | # 1821 | # Iterate over each line of the ascii art to retrieve the above 1822 | # information. The 'sed' is used to strip '\033[3Xm' color codes from 1823 | # the ascii art so they don't affect the width variable. 1824 | while read -r line; do 1825 | ascii_height=$((${ascii_height:-0} + 1)) 1826 | 1827 | # This was a ternary operation but they aren't supported in 1828 | # Minix's shell. 1829 | [ "${#line}" -gt "${ascii_width:-0}" ] && 1830 | ascii_width=${#line} 1831 | 1832 | # Using '<<-EOF' is the only way to loop over a command's 1833 | # output without the use of a pipe ('|'). 1834 | # This ensures that any variables defined in the while loop 1835 | # are still accessible in the script. 1836 | done <<-EOF 1837 | $(printf %s "$ascii" | sed 's/\[3.m//g') 1838 | EOF 1839 | 1840 | # Add a gap between the ascii art and the information. 1841 | ascii_width=$((ascii_width + 4)) 1842 | 1843 | # Print the ascii art and position the cursor back where we 1844 | # started prior to printing it. 1845 | { 1846 | esc_p SGR 1 1847 | printf '%s' "$ascii" 1848 | esc_p SGR 0 1849 | esc_p CUU "$ascii_height" 1850 | } >&6 1851 | } 1852 | 1853 | main() { 1854 | case $* in 1855 | -v) 1856 | printf '%s 0.7.0\n' "${0##*/}" 1857 | return 0 1858 | ;; 1859 | 1860 | -d) 1861 | # Below exec is not run, stderr is shown. 1862 | ;; 1863 | 1864 | '') 1865 | exec 2>/dev/null 1866 | ;; 1867 | 1868 | *) 1869 | cat <&6'. 1879 | # This gives full control over what it displayed on the screen. 1880 | exec 6>&1 >/dev/null 1881 | 1882 | # Store raw escape sequence character for later reuse. 1883 | esc_c=$(printf '\033') 1884 | 1885 | # Allow the user to execute their own script and modify or 1886 | # extend pfetch's behavior. 1887 | # shellcheck source=/dev/null 1888 | ! [ -f "$PF_SOURCE" ] || . "$PF_SOURCE" 1889 | 1890 | # Ensure that the 'TMPDIR' is writable as heredocs use it and 1891 | # fail without the write permission. This was found to be the 1892 | # case on Android where the temporary directory requires root. 1893 | [ -w "${TMPDIR:-/tmp}" ] || export TMPDIR=~ 1894 | 1895 | # Generic color list. 1896 | # Disable warning about unused variables. 1897 | # shellcheck disable=2034 1898 | for _c in c1 c2 c3 c4 c5 c6 c7 c8; do 1899 | esc SGR "3${_c#?}" 0 1900 | export "$_c=$e" 1901 | done 1902 | 1903 | # Disable line wrapping and catch the EXIT signal to enable it again 1904 | # on exit. Ideally you'd somehow query the current value and retain 1905 | # it but I'm yet to see this irk anyone. 1906 | esc_p DECAWM l >&6 1907 | trap 'esc_p DECAWM h >&6' EXIT 1908 | 1909 | # Store the output of 'uname' to avoid calling it multiple times 1910 | # throughout the script. 'read </dev/null || continue 1934 | 1935 | # This was a ternary operation but they aren't supported in 1936 | # Minix's shell. 1937 | [ "${#info}" -gt "${info_length:-0}" ] && 1938 | info_length=${#info} 1939 | done 1940 | 1941 | # Add an additional space of length to act as a gap. 1942 | info_length=$((info_length + 1)) 1943 | 1944 | # Iterate over the above list and run any existing "get_" functions. 1945 | for info do 1946 | "get_$info" 1947 | done 1948 | } 1949 | 1950 | # Position the cursor below both the ascii art and information lines 1951 | # according to the height of both. If the information exceeds the ascii 1952 | # art in height, don't touch the cursor (0/unset), else move it down 1953 | # N lines. 1954 | # 1955 | # This was a ternary operation but they aren't supported in Minix's shell. 1956 | [ "${info_height:-0}" -lt "${ascii_height:-0}" ] && 1957 | cursor_pos=$((ascii_height - info_height)) 1958 | 1959 | # Print '$cursor_pos' amount of newlines to correctly position the 1960 | # cursor. This used to be a 'printf $(seq X X)' however 'seq' is only 1961 | # typically available (by default) on GNU based systems! 1962 | while [ "${i:=0}" -le "${cursor_pos:-0}" ]; do 1963 | printf '\n' 1964 | i=$((i + 1)) 1965 | done >&6 1966 | } 1967 | 1968 | main "$@" 1969 | --------------------------------------------------------------------------------