linux: looking under the hood of neofetch

a couple of months ago, some semi-famous video game vlogger i’ve never heard of decided to get up on the linux soap box and rally his followers to ditch windows.

this was one of those viral-level, meme-type event things, and the result was a literal flood of screenshots of ‘riced’ desktops. and while each of those arch-newbie screeners was different than the last, they all had one common element: a terminal running neofetch.

this article is not going to be about neofetch specifically, but rather about the concepts and commands under neofetch‘s hood. we’re not going to rebuild this command, or go over it line-by-line. instead, we’re going to look at the basic tools we can use to inspect our linux system. by the end, we should be able to learn everything we want to about our linux-like system using standard, built-in commands and files. no neofetch required.

neofetch has always been a stack of linux commands, files and variables in a trenchcoat

inspecting our os with uname

uname stands for ‘unix name’ and, not surprisingly, it’s job is to give us the name of our operating system. but it also does a lot more. let’s start with the name:

$ uname -o
GNU/Linux

the -o switch here tells uname to tell us about the ‘operating system’. the response is simple, but accurate: GNU/Linux.

if we want to get some basic information on our system’s ‘processor’, we use the -p switch.

$ uname -p
x86_64

getting the exact kernel version we’re running is accomplished with -r.

$ uname -r
6.12.10-76061203-generic

files with more useful os information

the data from uname is correct, but not particularly useful. if we want something more detailed, there are some files we can look at, though.

the os-release file

the /etc/os-release file contains a lot of data about our system. this file is part of the systemd standard and has been around since 2012, so if you’re running a moderately modern linux-like operating system with systemd, it will be there.

let’s look at an example of its contents:

NAME="Pop!_OS"
VERSION="22.04 LTS"
ID=pop
ID_LIKE="ubuntu debian"
PRETTY_NAME="Pop!_OS 22.04 LTS"
VERSION_ID="22.04"
HOME_URL="https://pop.system76.com"
SUPPORT_URL="https://support.system76.com"
BUG_REPORT_URL="https://github.com/pop-os/pop/issues"
PRIVACY_POLICY_URL="https://system76.com/privacy"
VERSION_CODENAME=jammy
UBUNTU_CODENAME=jammy
LOGO=distributor-logo-pop-os

from this file, we can see that the user here is running pop_os 22.04. that’s some useful information!

the lsb-release file

an alternative to the os-release file is /etc/lsb-release. the ‘lsb’ here stands for ‘linux standard base’ which was an attempt made many years ago to unify and standardize all sorts of things across the various linux distros. stuff like the filesystem hierarchy, library versions, run levels and the like.

like most attempts at unification and standardization, it fell apart and lsb hasn’t been a going concern for over ten years now. however, there’s still a lot of lsb stuff lingering around in modern distros, and it’s useful.

let’s look at some sample output of /etc/lsb-release:

DISTRIB_ID=Pop
DISTRIB_RELEASE=22.04
DISTRIB_CODENAME=jammy
DISTRIB_DESCRIPTION="Pop!_OS 22.04 LTS"

exactly the sort of data we want.

our system may also include the binary lsb_release (mileage may vary). if it does, we can run it like so:

$ lsb_release -a
No LSB modules are available.
Distributor ID:	Pop
Description:	Pop!_OS 22.04 LTS
Release:	22.04
Codename:	jammy
‘linux standard base’ was abandoned in 2015

learning about memory with free

memory is complicated stuff. the traditional way to find out about free and used memory was to look in the /proc/meminfo file, but it’s an absolute mess in there.

if you want to stick with tradition, you can use grep to get just the ‘good bits’ from /proc/meminfo. something like this:

$ cat /proc/meminfo | grep -i "MemTotal\|MemFree"
MemTotal:       45141040 kB
MemFree:         6225932 kB

the alternative is to use the free command, which reports on ‘free’ memory:

$ free -h
               total        used        free      shared  buff/cache   available
Mem:            43Gi        11Gi       6.0Gi       396Mi        25Gi        27Gi
Swap:           19Gi       6.5Gi        13Gi

here we have passed the -h switch, which stands for ‘human readable’, ie megabytes and gigabytes instead of just raw kb.

there are two rows in the standard output: ‘Mem’ for physical, installed memory, and ‘Swap’ for swap space. if you don’t have a ‘Swap’ row, you should probably fix that. we’ll focus on physical memory.

the two columns we’re probably the most interested in are ‘total’ (the total amount of installed memory) and ‘free’.

‘free’ is calculated by adding the ‘used’ memory and the ‘buffer/cache’ memory and subtracting it from the total. this means that ‘used’ plus ‘buffer/cache’ plus ‘free’ adds up to our total memory:

$ free | grep 'Mem' | awk '{print $2 " = "$3" + "$4" + "$6}'
45141040 = 12235120 + 6080968 + 26824952
$ expr 12235120 + 6080968 + 26824952
45141040

and it does.

inspecting our hardware with lshw

the command lshw‘s long name is ‘hardware listener’, but everybody just says ‘list hardware’ instead because that’s what it does: it lists all our machine’s hardware.

let’s run it with the -short argument:

lshw -short

the output of this is a short description of every piece of hardware in our box. everything from our motherboard to our mouse to our cd burner, if we’re old enough to still have such a thing. if we want to, we can apply a little grep to filter for the information we need. for instance, to get just our processor and cdrom drive we could do:

$ sudo lshw -short | grep -i "processor\|cdrom"
/0/4                               processor      Intel(R) Core(TM) i7-4820K CPU @ 3.70GHz
/0/100/1d/1/1/3/0.0.0  /dev/cdrom  disk           DVDRAM GP65NB60

if we run lshw -short and look a the top line of the output, we see that the columns have these headings:

H/W path        Device      Class          Description
======================================================

if we want to do a more detailed exploration of our hardware, we will use the value under ‘Class’. so, for instance, for our cpu, the class is ‘processor’.

to inspect the hardware class, we use the -C switch and the class name like so:

$ lshw -C processor
  *-cpu                     
       product: Intel(R) Core(TM) i7-4820K CPU @ 3.70GHz
       vendor: Intel Corp.
       physical id: 1
       bus info: cpu@0
       version: 6.62.4
       size: 1200MHz
       capacity: 3900MHz
       width: 64 bits
       capabilities: fpu fpu_exception wp vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp x86-64 constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm cpuid_fault epb pti ssbd ibrs ibpb stibp tpr_shadow flexpriority ept vpid fsgsbase smep erms xsaveopt dtherm ida arat pln pts vnmi md_clear flush_l1d cpufreq
       configuration: microcode=1070

that’s a lot of information about our cpu.

we can do this with any class that lshw lists. for instance, if we want info on our video card, we can query the class ‘display’ (with a little bit of grep to cut out the noise)

$ lshw -C display | grep "product\|vendor"
       product: GP104 [GeForce GTX 1070]
       vendor: NVIDIA Corporation

getting info about hard disks with df

we can get some basic, but useful information about our hard drives using the df command. ‘df’ here stands for ‘disk free’ because most people use it to find out how much free space they have, but it does more than that. let’s look at some truncated sample output:

$ df -h
Filesystem                   Size  Used Avail Use% Mounted on
tmpfs                        4.4G  2.5M  4.4G   1% /run
/dev/sda1                    1.8T  791G  946G  46% /
192.168.1.70:/volume1/music  3.6T  457G  3.2T  13% /mnt/music

in this example we’ve run df with the -h switch to use ‘human readable’ units.

from this we can see that there is one 1.8 terabyte hard drive mounted on the root partition and it’s 46% full. there’s also a network drive mounted on mnt/music.

for most purposes, this level of detail is sufficient. however, if we want a bit more, we can use lsblk to list all our ‘block devices’.

lsblk

the output of this command will show drives (including things like our cdrom) and their partitions. it will also show every single snap we have installed as a device.

if we want to know the filesystems of our drives, we can pass the --fs switch

lsblk --fs

finding our screen resolution

if we want to get our current screen resolutions and all possible supported resolutions, we can use xrandr.

as that ‘x’ at the beginning of the name implies, xrandr is an xwindow tool. if we are using wayland, instead, we’ll need to find an alternate solution such as wlr-randr

running xrander gives us the following output:

$ xrandr
Screen 0: minimum 8 x 8, current 2560 x 1440, maximum 32767 x 32767
DVI-D-0 disconnected (normal left inverted right x axis y axis)
HDMI-0 connected primary 2560x1440+0+0 (normal left inverted right x axis y axis) 697mm x 392mm
   3840x2160     60.00 +  59.94    50.00    30.00    29.97    25.00    23.98  
   2560x1440     59.95* 
   1920x1080     60.00    59.94    50.00    29.97    23.98  
   1680x1050     59.95  
   1600x900      60.00  
   1440x900      59.89  
   1280x1024     75.02    60.02  
   1280x800      59.81  
   1280x720      60.00    59.94    50.00  
   1152x864      75.00  
   1024x768      75.03    70.07    60.00  
   800x600       75.00    72.19    60.32    56.25  
   720x576       50.00  
   720x480       59.94  
   640x480       75.00    72.81    59.94 

here we can see that our current resolution is 2560×1440. there’s also a lengthy output of supported resolutions.

deducing our desktop environment

lots of people use graphical desktop environments in linux, so finding out what’s being run is probably important. we can get that information from the $XDG_CURRENT_DESKTOP environmental variable:

$ echo $XDG_CURRENT_DESKTOP
pop:GNOME

once we know what desktop environment is being run, we can call it directly to get the version number:

$ gnome-shell --version
GNOME Shell 42.9

for kde, we would use:

plasmashell --version

other desktop environments will have their own commands that accept the --version argument.

getting the current shell

the default shell of the current user is stored in the $SHELL environmental variable. we can access it like this:

$ echo $SHELL
/usr/bin/fish

if we want to retrieve the version of the shell, we can use $SHELL as an executable and pass the --version argument

$ $SHELL --version
fish, version 3.7.1

if we need to get the shell for a user other than the one we are logged in as, we can always retrieve it from the /etc/passwd file:

$ cat /etc/passwd | grep ghorwood
ghorwood:x:1000:1000:grant horwood:/home/ghorwood:/usr/bin/fish

finding up time with uptime

it’s a ridiculous point of pride for some linux users that they never have to reboot their machines. we can find out how long our box has been up and running with the uptime command:

$ uptime -p
up 2 weeks, 4 days, 18 hours

eighteen days isn’t bad.

Conclusion

neofetch is a useful and fun tool, but learning how it finds data about our machine gives us a better understanding of our operating system.

Posted by: grant horwood

co-founder of fruitbat studios. cli-first linux snob, metric evangelist, unrepentant longhair. all the music i like is objectively horrible. he/him.

Leave a Reply