How to Let Linux Scripts Detect They’re Running in Virtual Machines

Two hands, one holding a red pill and the other a blue pill.

 

Virtual machines try really hard to convince their operating systems that they’re running on physical hardware. So can you tell from the Linux command line if the computer is physical or virtual?

Virtual Machines and Hypervisors

A traditional computer is a physical object. It’s a collection of different pieces of hardware that are plugged and bolted together so that you can load an operating system, install applications, launch them, and use them.

Hardware is expensive. Being restricted to one operating system per physical computer means the cost of running several operating systems soon becomes prohibitive. A better solution would be to allow a single physical computer to run a selection of operating systems at the same time, with each one thinking it’s running in its own, unique hardware.

A hypervisor makes this possible. A hypervisor—also called a virtual machine manager or virtual machine monitor—is software that lets you create virtual machines. These behave as though they were individual, physical computers although they run on the same physical host, sharing its hard drive space, memory, and CPU cores.

Of course, the host computer has to be powerful enough to cope with the demands of the collection of virtual machines, but, given sufficient RAM and processing power in the host, virtual machines can run at near bare-metal speeds.

Since the release of the 2.6.20 kernel in 2007, Linux has had Kernel-based Virtual Machine support baked right in. Linux has several hypervisors available to it, such as VirtualBox, GNOME Boxes, and QEMU-KVM. They make use of the native KVM capability of Linux, building upon the native kernel functionality by adding user interfaces and functionality such as being able to take a snapshot of a virtual machine.

Virtual machines bring cost savings, efficiencies, simplified deployments, and—provisioned correctly—security benefits. They also facilitate scalability. New servers can be automatically spun up as demand for a service increases and shut down when demand drops. This makes them hugely popular both in the cloud and in on-premise infrastructure.

Perhaps you’re remotely administering a Linux server and you need to know whether it is a virtual machine or a physical box. Or you have a script that needs to know what type of platform it is executing on. Here are several ways you can detect if the computer you’re working on is physical or virtual.

The dmidecode Command

The dmidecode command supports a large number of options and modifiers. It interrogates the Desktop Management Interface (DMI) tables, and prints the information in the terminal window.

We’ll use it with the -s (display a single string) option, and ask for the system product name. Note that we must use sudo.

We’ll run the command on a VirtualBox VM running Ubuntu 22.04.

sudo dmidecode -s system-product-name

The dmidecode command correctly identifying a VirtualBox VM

The platform is correctly identified as VirtualBox.

On a QEMU-KVM VM running Fedora 35, we get this output.

sudo dmidecode -s system-product-name

The dmidecode command correctly identifying a GNOME Boxes VM

Although this is reported as a standard PC, it is a standard QEMU virtual PC, of type Q35. So the platform is correctly recognized as a virtual machine.

If we run the same command on a physical computer we get some information about the manufacturer.

sudo dmidecode -s system-product-name

The dmidecode command returning information about a physical computer

This computer is a custom-build based on a Micro-Star International Company Limited motherboard, with the product code of MS-7B86.

The lshw Command

The lshw command lists the details for a wide range of computer hardware. We can choose which class of hardware we want lshw to report on.

We’re going to use the -class option with the system modifier. Using sudo with this command ensures we see all of the detail.

We’ll run this command on our Ubuntu VirtualBox VM.

sudo lshw -class system

The lshw command reporting on a VirtualBox VM

  • The “description” field has a generic entry of “computer.”
  • The “product” field tells us this is a virtual machine running in VirtualBox.
  • The “vendor” field contains the name of the German company that created VirtualBox, Innotek GmbH. Innotek was acquired by the Oracle Corporation in 2010 as part of its acquisition of Sun Microsystems, Inc.

We had to install lshw on Fedora.

sudo dnf install lshw

Installing lshw on Fedora with the dnf command

Let’s try that command in our Fedora VM running in GNOME Boxes.

sudo lshw -class system

The lshw command reporting on a GNOME Boxes VM

  • Again, the “description” field has a generic entry of “computer.”
  • The “product” field gives us the same standard QEMU PC information that we saw with the dmidecode command.
  • The “vendor” field contains “QEMU” which quite clearly indicates this is a virtual machine.

This is the result of running the same command on our physical computer.

sudo lshw -class system

The lshw command reporting on a physical computer

We can see that this is a hardware computer, with a Micro-Star motherboard.

  • The hardware is identified as a desktop computer.
  • The “product” field gives us the motherboard type, MS-7B86.
  • The “vendor” field contains the manufacturer’s name.

The hostnamectl Command

This command has the advantage that you don’t need to have sudo privileges to run it. However, it is only available on systemd-enabled distributions. The majority of modern distributions use systemd.

This is the response from running the command on our Ubuntu VirtualBox VM.

hostnamectl

The output from the hostnamectl command in a VirtualBox VM with the virtualization line highlighted

  • The “icon-name” field has “-vm” appended to it.
  • The “Chassis” field contains “vm.”
  • The “Virtualization” field contains “oracle.”
  • The “Hardware Vendor” field contains “innotek GmbH.”
  • The “Hardware Model” field contains “VirtualBox.”

The output on our Fedora VM inside GNOME Boxes is very similar.

hostnamectl

The output from the hostnamectl command in a GNOME Boxes VM with the virtualization line highlighted

  • The “icon-name” field has “-vm” appended to it.
  • The “Chassis” field contains “vm.”
  • The “Virtualization” field contains “kvm.”
  • The “Hardware Vendor” field contains “QEMU”
  • The “Hardware Model” field contains “Standard PC (Q35 + ICH9, 2009).”

If we use the hostnamectl command on our physical desktop, the output doesn’t contain a “Virtualization” line.

hostnamectl

The output from the hostnamectl command on a physical computer, with no "Virtualization" information

If there’s no “Virtualization” field, you must be running on bare metal.

The systemd-detect-virt Command

If you want to get as short an answer as possible, systemd-detect-virt is probably what you’re looking for. Again this requires a systemd-equipped distribution, but it doesn’t require sudo privileges. This—and its terse output—make it well suited for use in scripts.

This is the result of running the command on our Ubuntu VirtualBox VM.

systemd-detect-virt

Identifying a VirtualBox VM with systemd-detect-virt

Our copy of Fedora running in GNOME Boxes is reported as using KVM virtualization.

systemd-detect-virt

Identifying a GNOME Boxes VM with systemd-detect-virt

Running systemd-detect-virt on our hardware machine results in “none” being printed to the terminal.

systemd-detect-virt

A physical computer being correctly identified as having no virtualization

A Platform-Sensitive Script

To give a script the ability to detect whether it is running in a virtualized environment or on physical hardware, we can use the systemd-detect-virt command and use Bash case statements to handle the options.

This is the script we’ll use. Copy this text and save it into a file called “platform.sh.”

#!/bin/bash

shopt -s nocasematch

case $(systemd-detect-virt) in

  none)
    echo "Physical Hardware"
    ;;

  *)
    echo "Virtual Machine"
    ;;
esac

The script uses shopt to choose case-insensitive matching. The systemd-detect-virt command is used in the case statement. The output from this command is compared with each of the case clauses in the body of the case statement until a match is found. Anything that isn’t matched is captured by the “*)” default clause.

The simplest way is to test if the response from systemd-detect-virt is “none.” If it is, the script is running on physical hardware. For all other cases, the script must be running on a virtual machine.

Before we can run the script we must make it executable, using chmod.

chmod +x platform.sh

Making the platform script executable with chmod

It correctly identifies our Ubuntu VirtualBox VM as a virtual machine.

./platform.sh

Using the platform.sh script in a VirtualBox VM

It also correctly detects the GNOME Boxes VM running Fedora.

./platform.sh

Using the platform.sh script in a GNOME Boxes VM

The script also correctly detects when it is running on a physical machine.

./platform.sh

Using the platform.sh script on a physical computer

The different case clauses could set variables that were checked elsewhere in the script to perform different types of processing, or they could call specific functions within your script.

If your script needed to detect and accommodate different types of virtual environments, you could add more case clauses, looking for the different strings that systemd-detect-virt can return. We can see the complete list of possible responses by using the --list option. To make it easier to see them all at once, we’ll pipe the output through the column command.

systemd-detect-virt --list | column

The complete set of responses that systemd-detect-virt can return

Rolar para cima