├── .editorconfig
├── .github
└── workflows
│ └── main.yml
├── LICENSE.md
├── Makefile
├── README.md
└── pfetch
/.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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |

2 | pfetch
3 | A pretty system information tool written in POSIX sh
4 |
5 |
6 |
7 | The goal of this project is to implement a simple system
8 | information tool in POSIX `sh` using features built into
9 | the language itself (*where possible*).
10 |
11 | The source code is highly documented and I hope it will
12 | act as a learning resource for POSIX `sh` and simple
13 | information detection across various different operating
14 | systems.
15 |
16 | If anything in the source code is unclear or is lacking
17 | in its explanation, open an issue. Sometimes you get too
18 | close to something and you fail to see the "bigger
19 | picture"!
20 |
21 |
22 |
23 |
24 |
25 |
26 | ## OS support
27 |
28 | - **Linux**
29 | - Alpine Linux, Arch Linux, Arco Linux, Artix Linux, CentOS, Dahlia, Debian, Devuan, Elementary, EndeavourOS, Fedora, Garuda Linux, Gentoo, Guix, Hyperbola, instantOS, KISS Linux, Linux Lite, Linux Mint, Mageia, Manjaro, MX Linux, NixOS, OpenSUSE, Parabola, Pop!\_OS, PureOS, Slackware, Solus, Ubuntu and Void Linux.
30 | - All other distributions are supported with a generic penguin logo.
31 | - **Android**
32 | - **BSD**
33 | - DragonflyBSD, FreeBSD, NetBSD and OpenBSD.
34 | - **Windows**
35 | - Windows subsystem for Linux.
36 | - **Haiku**
37 | - **MacOS**
38 | - **Minix**
39 | - **Solaris**
40 | - **IRIX**
41 | - **SerenityOS**
42 |
43 | ## Configuration
44 |
45 | `pfetch` is configured through environment variables.
46 |
47 | ```sh
48 | # Which information to display.
49 | # NOTE: If 'ascii' will be used, it must come first.
50 | # Default: first example below
51 | # Valid: space separated string
52 | #
53 | # OFF by default: shell editor wm de palette
54 | PF_INFO="ascii title os host kernel uptime pkgs memory"
55 |
56 | # Example: Only ASCII.
57 | PF_INFO="ascii"
58 |
59 | # Example: Only Information.
60 | PF_INFO="title os host kernel uptime pkgs memory"
61 |
62 | # A file to source before running pfetch.
63 | # Default: unset
64 | # Valid: A shell script
65 | PF_SOURCE=""
66 |
67 | # Separator between info name and info data.
68 | # Default: unset
69 | # Valid: string
70 | PF_SEP=":"
71 |
72 | # Enable/Disable colors in output:
73 | # Default: 1
74 | # Valid: 1 (enabled), 0 (disabled)
75 | PF_COLOR=1
76 |
77 | # Color of info names:
78 | # Default: unset (auto)
79 | # Valid: 0-9
80 | PF_COL1=4
81 |
82 | # Color of info data:
83 | # Default: unset (auto)
84 | # Valid: 0-9
85 | PF_COL2=9
86 |
87 | # Color of title data:
88 | # Default: unset (auto)
89 | # Valid: 0-9
90 | PF_COL3=1
91 |
92 | # Alignment padding.
93 | # Default: unset (auto)
94 | # Valid: int
95 | PF_ALIGN=""
96 |
97 | # Which ascii art to use.
98 | # Default: unset (auto)
99 | # Valid: string
100 | PF_ASCII="openbsd"
101 |
102 | # The below environment variables control more
103 | # than just 'pfetch' and can be passed using
104 | # 'HOSTNAME=cool_pc pfetch' to restrict their
105 | # usage solely to 'pfetch'.
106 |
107 | # Which user to display.
108 | USER=""
109 |
110 | # Which hostname to display.
111 | HOSTNAME=""
112 |
113 | # Which editor to display.
114 | EDITOR=""
115 |
116 | # Which shell to display.
117 | SHELL=""
118 |
119 | # Which desktop environment to display.
120 | XDG_CURRENT_DESKTOP=""
121 | ```
122 |
123 | ## Credit
124 |
125 | - [ufetch](https://gitlab.com/jschx/ufetch): Lots of ASCII logos.
126 | - Contrary to the belief of a certain youtuber, `pfetch` shares **zero** code with `ufetch`. Only some of the ASCII logos were used.
127 |
--------------------------------------------------------------------------------
/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 | (*)
1792 | # On no match of a distribution ascii art, this function calls
1793 | # itself again, this time to look for a more generic OS related
1794 | # ascii art (KISS Linux -> Linux).
1795 | [ "$1" ] || {
1796 | get_ascii "$os"
1797 | return
1798 | }
1799 |
1800 | printf 'error: %s is not currently supported.\n' "$os" >&6
1801 | printf 'error: Open an issue for support to be added.\n' >&6
1802 | exit 1
1803 | ;;
1804 | esac
1805 |
1806 | # Store the "width" (longest line) and "height" (number of lines)
1807 | # of the ascii art for positioning. This script prints to the screen
1808 | # *almost* like a TUI does. It uses escape sequences to allow dynamic
1809 | # printing of the information through user configuration.
1810 | #
1811 | # Iterate over each line of the ascii art to retrieve the above
1812 | # information. The 'sed' is used to strip '\033[3Xm' color codes from
1813 | # the ascii art so they don't affect the width variable.
1814 | while read -r line; do
1815 | ascii_height=$((${ascii_height:-0} + 1))
1816 |
1817 | # This was a ternary operation but they aren't supported in
1818 | # Minix's shell.
1819 | [ "${#line}" -gt "${ascii_width:-0}" ] &&
1820 | ascii_width=${#line}
1821 |
1822 | # Using '<<-EOF' is the only way to loop over a command's
1823 | # output without the use of a pipe ('|').
1824 | # This ensures that any variables defined in the while loop
1825 | # are still accessible in the script.
1826 | done <<-EOF
1827 | $(printf %s "$ascii" | sed 's/\[3.m//g')
1828 | EOF
1829 |
1830 | # Add a gap between the ascii art and the information.
1831 | ascii_width=$((ascii_width + 4))
1832 |
1833 | # Print the ascii art and position the cursor back where we
1834 | # started prior to printing it.
1835 | {
1836 | esc_p SGR 1
1837 | printf '%s' "$ascii"
1838 | esc_p SGR 0
1839 | esc_p CUU "$ascii_height"
1840 | } >&6
1841 | }
1842 |
1843 | main() {
1844 | case $* in
1845 | -v)
1846 | printf '%s 0.7.0\n' "${0##*/}"
1847 | return 0
1848 | ;;
1849 |
1850 | -d)
1851 | # Below exec is not run, stderr is shown.
1852 | ;;
1853 |
1854 | '')
1855 | exec 2>/dev/null
1856 | ;;
1857 |
1858 | *)
1859 | cat <&6'.
1869 | # This gives full control over what it displayed on the screen.
1870 | exec 6>&1 >/dev/null
1871 |
1872 | # Store raw escape sequence character for later reuse.
1873 | esc_c=$(printf '\033')
1874 |
1875 | # Allow the user to execute their own script and modify or
1876 | # extend pfetch's behavior.
1877 | # shellcheck source=/dev/null
1878 | ! [ -f "$PF_SOURCE" ] || . "$PF_SOURCE"
1879 |
1880 | # Ensure that the 'TMPDIR' is writable as heredocs use it and
1881 | # fail without the write permission. This was found to be the
1882 | # case on Android where the temporary directory requires root.
1883 | [ -w "${TMPDIR:-/tmp}" ] || export TMPDIR=~
1884 |
1885 | # Generic color list.
1886 | # Disable warning about unused variables.
1887 | # shellcheck disable=2034
1888 | for _c in c1 c2 c3 c4 c5 c6 c7 c8; do
1889 | esc SGR "3${_c#?}" 0
1890 | export "$_c=$e"
1891 | done
1892 |
1893 | # Disable line wrapping and catch the EXIT signal to enable it again
1894 | # on exit. Ideally you'd somehow query the current value and retain
1895 | # it but I'm yet to see this irk anyone.
1896 | esc_p DECAWM l >&6
1897 | trap 'esc_p DECAWM h >&6' EXIT
1898 |
1899 | # Store the output of 'uname' to avoid calling it multiple times
1900 | # throughout the script. 'read </dev/null || continue
1924 |
1925 | # This was a ternary operation but they aren't supported in
1926 | # Minix's shell.
1927 | [ "${#info}" -gt "${info_length:-0}" ] &&
1928 | info_length=${#info}
1929 | done
1930 |
1931 | # Add an additional space of length to act as a gap.
1932 | info_length=$((info_length + 1))
1933 |
1934 | # Iterate over the above list and run any existing "get_" functions.
1935 | for info do
1936 | "get_$info"
1937 | done
1938 | }
1939 |
1940 | # Position the cursor below both the ascii art and information lines
1941 | # according to the height of both. If the information exceeds the ascii
1942 | # art in height, don't touch the cursor (0/unset), else move it down
1943 | # N lines.
1944 | #
1945 | # This was a ternary operation but they aren't supported in Minix's shell.
1946 | [ "${info_height:-0}" -lt "${ascii_height:-0}" ] &&
1947 | cursor_pos=$((ascii_height - info_height))
1948 |
1949 | # Print '$cursor_pos' amount of newlines to correctly position the
1950 | # cursor. This used to be a 'printf $(seq X X)' however 'seq' is only
1951 | # typically available (by default) on GNU based systems!
1952 | while [ "${i:=0}" -le "${cursor_pos:-0}" ]; do
1953 | printf '\n'
1954 | i=$((i + 1))
1955 | done >&6
1956 | }
1957 |
1958 | main "$@"
1959 |
--------------------------------------------------------------------------------