├── 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 |
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 |
--------------------------------------------------------------------------------