When you take over an unfamiliar Linux machine — a new server rack, a hand-me-down workstation, a cloud instance with a mystery instance type — the first thing you need is a clear picture of the hardware underneath the OS. Kernel logs tell part of the story, but four command-line tools give you the complete picture: lspci, dmidecode, lshw, and inxi. Each reads from different sources, covers different hardware layers, and serves a different use case. This article covers all four in enough depth to use them confidently in production.
Most of these commands either require root or produce significantly richer output when run as root. Where sudo matters, it's noted explicitly. On systems with the wheel group configured for sudo access, substitute as appropriate for your environment.
lspci: Reading the PCI Bus
lspci is part of the pciutils package and queries the kernel's PCI subsystem — specifically /sys/bus/pci and /proc/bus/pci — to enumerate every device connected over PCI, PCIe, or a PCI bridge. That covers the vast majority of modern system components: GPUs, NVMe controllers, network adapters, USB host controllers, SATA controllers, and sound cards.
On Debian/Ubuntu systems, install it with apt install pciutils. On Fedora/RHEL it comes pre-installed; on Arch, pacman -S pciutils.
The default output is deliberately compact — one line per device showing the bus address, device class, and a short description. For production use you'll almost always want more:
# Verbose output -- device capabilities, interrupt lines, memory regions $ lspci -v # Very verbose -- includes kernel driver in use and available kernel modules $ lspci -k # Show numeric vendor:device IDs alongside human-readable names $ lspci -nn # Machine-readable output -- useful for scripting $ lspci -mm # Show bus tree topology $ lspci -t # Combine: full verbose output with driver info and numeric IDs $ lspci -nnkv
The -k flag is particularly useful when troubleshooting driver issues. It shows both the kernel driver currently bound to the device and any other kernel modules that could handle it. This is how you quickly confirm whether your 10GbE adapter is running ixgbe or mlx5_core, and whether the right one is actually loaded.
Filtering lspci Output
On dense server hardware with dozens of PCI devices, piping through grep is common. But lspci also has a built-in filter with -d for vendor and device ID, and -s for bus address. The -d flag accepts the format vendor:device using the numeric IDs shown by -nn:
# Show only NVIDIA devices (vendor ID 10de) $ lspci -d 10de: -nnkv # Show only network controllers $ lspci | grep -i 'network\|ethernet\|wireless' # Show only storage controllers $ lspci | grep -i 'sata\|nvme\|raid\|storage' # Examine a specific device by bus address (e.g., 03:00.0) $ lspci -s 03:00.0 -vvv
The PCI ID database lspci uses to translate numeric IDs to vendor names lives at /usr/share/misc/pci.ids or /usr/share/hwdata/pci.ids. If a device shows as Unknown device, run sudo update-pciids to pull a fresh copy from the pci-ids.ucw.cz database. This matters on new hardware where the distro's packaged database predates the device.
dmidecode: Reading BIOS and SMBIOS Tables
dmidecode reads the SMBIOS (System Management BIOS) table — a firmware-level data structure that the BIOS or UEFI populates with information about the hardware platform. This includes data that the OS kernel doesn't expose directly: the exact memory module part numbers, chassis serial numbers, BIOS version and release date, processor socket designations, and slot configurations.
It reads from /sys/firmware/dmi/tables on modern kernels (a privileged sysfs path) or directly from /dev/mem on older ones. Either way, sudo is required.
Without flags, dmidecode dumps the entire SMBIOS table — hundreds of lines covering every hardware type. In practice you'll nearly always filter by type:
# BIOS version, release date, and firmware revision $ sudo dmidecode -t bios # System manufacturer, product name, serial number, UUID $ sudo dmidecode -t system # Baseboard (motherboard) manufacturer and product $ sudo dmidecode -t baseboard # Processor socket, speed, core/thread count $ sudo dmidecode -t processor # Memory slots: size, speed, part number, manufacturer per DIMM $ sudo dmidecode -t memory # Physical expansion slot types and status (occupied/available) $ sudo dmidecode -t slot # Chassis type, serial, lock status $ sudo dmidecode -t chassis
The memory type output deserves special attention. Unlike /proc/meminfo which only tells you total and available RAM, dmidecode -t memory enumerates every physical memory slot on the board — including empty ones — and for populated slots shows the speed, size, ECC capability, manufacturer, part number, and serial number. This is how you verify that a server has the right DIMMs installed before a warranty claim, or confirm that a memory upgrade actually landed in the correct channels for interleaving.
Memory Device Array Handle: 0x1000 Error Information Handle: 0x1100 Total Width: 72 bits Data Width: 64 bits Size: 32 GB Form Factor: DIMM Locator: DIMM_A1 Bank Locator: NODE 1 CHANNEL A DIMM 0 Type: DDR5 Speed: 4800 MT/s Manufacturer: Samsung Serial Number: 3A45BE91 Part Number: M321R4GA3BB6-CQKOL Configured Memory Speed: 4800 MT/s ECC: Yes
The numeric type codes are an alternative to keyword strings. Type 0 is BIOS, type 17 is memory device, type 4 is processor, and so on. The full table is in the dmidecode man page. You can also use sudo dmidecode -t 17 instead of sudo dmidecode -t memory — both work.
SMBIOS data is written by the firmware vendor and can be inaccurate, incomplete, or contain placeholder strings like "To Be Filled By O.E.M." on budget hardware. Always cross-reference critical values (especially memory speed) against what the kernel actually negotiated, visible in dmesg | grep -i ddr or the UEFI setup screen.
Extracting Specific Fields for Scripting
For automation — generating asset inventory reports, pre-flight checks before OS deployment, or populating a CMDB — you can combine dmidecode with string selection to extract clean values:
# Get just the system serial number $ sudo dmidecode -s system-serial-number # Get the BIOS version string $ sudo dmidecode -s bios-version # Get the system product name (model) $ sudo dmidecode -s system-product-name # List all available -s keywords $ sudo dmidecode --string help
The -s flag outputs a single clean string with no surrounding text — ideal for shell variable assignment or piping into a configuration management tool. This pairs well with bash scripting for inventory automation across multiple hosts.
lshw: The Full Hardware Tree
lshw (list hardware) takes a broader approach than the previous two tools by aggregating data from multiple sources simultaneously: /proc, /sys, SMBIOS via DMI, the PCI bus, and udev events. The result is a structured hardware tree covering the entire system — firmware, CPU, memory, storage controllers and attached disks, network interfaces, PCI devices, USB buses, and more.
Install it with apt install lshw, dnf install lshw, or pacman -S lshw depending on your distribution. Running it as root gives the most complete output.
The default text output is thorough but long. For most use cases, the short table or class-filtered output is more practical:
# Condensed table: class, description, product, vendor, logical name $ sudo lshw -short # Filter to a specific hardware class $ sudo lshw -class network $ sudo lshw -class storage $ sudo lshw -class disk $ sudo lshw -class processor $ sudo lshw -class memory # Export as HTML report (good for documentation) $ sudo lshw -html > hardware-report.html # Export as JSON for machine processing $ sudo lshw -json > hardware.json # Quiet mode -- suppress warnings about /proc access $ sudo lshw -quiet
The -short output is often the fastest way to orient yourself on an unfamiliar system. It condenses everything into a readable table with hardware paths that reflect the physical bus hierarchy — you can see at a glance that your NVMe is on PCIe bus 1, your SATA controller is on bus 0, and your dual-port NIC is in slot 3.
H/W path Device Class Description ======================================================== system PowerEdge R750 /0 bus 0XDYHM /0/0 memory 128GiB System Memory /0/0/0 memory 32GiB DIMM DDR5 4800 MHz /0/0/1 memory 32GiB DIMM DDR5 4800 MHz /0/1 processor Intel Xeon Gold 6338 /0/100 bridge Sky Lake PCIe Controller /0/100/1/0 storage NVMe SSD Controller /0/100/1/0/0 /dev/nvme0 disk 1.92TB Samsung PM9A3 /0/100/1c/0 eno1 network Intel X550 10GbE
Using lshw for Network Interface Inventory
The network class filter is especially useful when documenting server NICs before configuration. It shows the interface name, MAC address, driver, firmware version, link speed capability, and whether auto-negotiation is enabled — all the information you need before writing an /etc/network/interfaces or configuring Ubuntu Server network management rules:
$ sudo lshw -class network *-network description: Ethernet interface product: Ethernet Controller X550 vendor: Intel Corporation logical name: eno1 version: 01 serial: a4:bf:01:23:45:67 capacity: 10Gbit/s driver: ixgbe firmware: 0x800012c3 link: yes autonegotiation: on
The JSON output from sudo lshw -json is well-structured and easy to parse with jq. For fleet-wide hardware inventory, you can script this across hosts with SSH and aggregate the JSON into a central database. Pair it with port scanning tools to correlate network interface data with active services.
inxi: The System Summary Tool
inxi is a Perl script with a different goal from the three tools above. Where lspci, dmidecode, and lshw are diagnostic tools designed to give you raw hardware data, inxi is designed to produce readable, shareable system summaries. It pulls from lspci, dmidecode, /proc, /sys, and several other sources, then formats the output with human-readable labels and sensible defaults.
It's the tool you paste into a forum post or bug report when you need to describe your system quickly. It's also useful for sysadmins who need a fast overview without parsing walls of raw data.
Install it with apt install inxi, dnf install inxi, or pacman -S inxi.
The three flags here are the standard starting point: -F for full output, -x for extra detail, and -z to anonymize private data like serial numbers and MAC addresses. On a system where you're sharing output publicly, -z is important.
# Full summary with extra details, private data anonymized $ inxi -Fxz # CPU info only $ inxi -C # Graphics/GPU only $ inxi -G # Memory info $ inxi -m # Network interfaces only $ inxi -N # Disk/storage summary $ inxi -D # RAID arrays if present $ inxi -R # Temperatures, fan speeds, voltages (requires lm-sensors) $ inxi -s # Running processes $ inxi -t # Repository and package info $ inxi -r
The sensor output (-s) is particularly useful when you suspect thermal issues — it aggregates CPU, GPU, and motherboard temperatures into a single readable view without needing to install and configure additional monitoring tools.
System: Host: web01 Kernel: 6.8.0-55-generic x86_64 OS: Ubuntu 24.04.2 LTS CPU: Info: 32-core Intel Xeon Gold 6338 [MT MCP] Speed: 2100 MHz min/max: 800/3200 MHz Graphics: Device-1: ASPEED AST2600 driver: ast Network: Device-1: Intel Ethernet X550 driver: ixgbe IF: eno1 state: up speed: 10000 Mbps duplex: full Device-2: Intel Ethernet X550 driver: ixgbe IF: eno2 state: down Drives: Local Storage: total: 3.84 TiB ID-1: /dev/nvme0n1 vendor: Samsung model: MZQL21T9HCJR size: 1.92 TiB ID-2: /dev/nvme1n1 vendor: Samsung model: MZQL21T9HCJR size: 1.92 TiB Partition: ID-1: / size: 1.82 TiB used: 214.3 GiB (11.5%) fs: ext4 Memory: RAM: total: 125.72 GiB used: 22.14 GiB (17.6%) Info: Processes: 412 Uptime: 47 days Shell: bash
inxi on Minimal Server Installations
On minimal server installs, inxi may produce warnings about missing optional dependencies. These are informational — it will still output what it can. For full functionality including temperature readings, install lm-sensors and run sudo sensors-detect. For SMART disk health data alongside the drive listing, install smartmontools.
On headless servers where terminal color codes cause problems in logs or monitoring systems, run inxi --no-color to strip ANSI escape sequences from the output. This also makes the output easier to diff across runs when tracking hardware changes over time.
Choosing the Right Tool
The four tools overlap in some areas but each has a clear primary use case. Understanding where each one draws its data from helps you choose the right one for the job:
- lspci — when you need PCI/PCIe device details, driver bindings, or bus topology. Fast, no root required for basic output, and ideal for driver troubleshooting. Pairs well with reviewing systemd units that manage hardware-dependent services.
- dmidecode — when you need firmware-level data: BIOS version, memory module part numbers, chassis serials, processor socket info. Requires root. The authoritative source for SMBIOS data. Essential for warranty work, asset management, and pre-deployment verification.
- lshw — when you need a comprehensive hardware inventory across all subsystems in a single command. Best for documentation, onboarding unfamiliar hardware, and generating exportable reports. The JSON output integrates well with configuration management tooling. For kernel-level analysis see also Linux kernel tuning for high-traffic servers.
- inxi — when you need a quick readable summary, especially for sharing. The
-zflag makes it safe to paste publicly. The sensor integration makes it useful as a quick health check without writing a custom monitoring query.
The most productive habit is running
sudo lshw -shortandinxi -Fxzas part of any new-system checklist. Two commands, two minutes, complete hardware picture.
How to Inspect Linux Hardware From the Command Line
Step 1: Query PCI devices with lspci
Run lspci to list all PCI and PCIe devices. Add the -v flag for verbose output, -k to show kernel drivers in use, or -nn to include vendor and device ID codes alongside human-readable names. Use lspci -nnkv for the most complete single-pass view of PCI hardware and its driver bindings.
Step 2: Read BIOS and SMBIOS data with dmidecode
Run sudo dmidecode to dump the full SMBIOS table. Use the -t flag with a type keyword such as sudo dmidecode -t memory to filter output to a specific hardware category. Use the -s flag with a string keyword such as sudo dmidecode -s system-serial-number for clean single-value output suitable for scripting.
Step 3: Generate a full hardware tree with lshw
Run sudo lshw -short for a condensed hardware table showing bus hierarchy, or sudo lshw -class network to filter by a specific hardware class. Use sudo lshw -json to export machine-readable output for inventory automation, or sudo lshw -html to generate an HTML report for documentation.
Step 4: Get a system summary with inxi
Run inxi -Fxz for a full system summary with extra detail and private information anonymized. Use component-specific flags like inxi -G for graphics, inxi -N for network, or inxi -s for thermal sensor readings. Add --no-color when capturing output for logs or monitoring pipelines.
Frequently Asked Questions
What is the difference between lspci and lshw on Linux?
lspci shows only PCI and PCIe-connected devices by querying the kernel's PCI subsystem. lshw produces a full hardware tree covering CPU, memory, storage, firmware, and more by reading multiple sources including /proc, /sys, and DMI data. Use lspci for a fast PCI-only view and lshw when you need a comprehensive hardware inventory.
Why does dmidecode require sudo on Linux?
dmidecode reads the SMBIOS/DMI table directly from /dev/mem or /sys/firmware/dmi/tables, which is a privileged memory region. Reading from /dev/mem requires root access on most distributions because unrestricted memory reads could expose sensitive data or be abused to interact with hardware. On modern kernels the sysfs path is preferred, but it remains root-only.
Does inxi work on all Linux distributions?
inxi is a Perl script available in the package repositories of most major Linux distributions including Debian, Ubuntu, Fedora, Arch, and openSUSE. It can be installed via apt, dnf, pacman, or zypper. On minimal server installs it may not be present by default and requires manual installation. It will run with reduced output if optional dependencies like lm-sensors or smartmontools are missing.