Use Python to get a variety of information about Linux systems

Source: Internet
Author: User
Tags glob
In this article, we will explore the use of Python programming language tools to retrieve various information about Linux systems. Walk you.

Which Python version?

When I mentioned Python, I was referring to CPython 2 (exactly 2.7). I will explicitly remind those same code that it is not working on CPython 3 (3.3) and provide an alternative code that explains the differences. Make sure you have CPython installed, enter Python or Python3 carriage return on the terminal, and you should see the Python prompt (prompt) on the terminal.

Note that all the programs in their first line are #!/usr/bin/env/python, that is, we want the Python interpreter to execute these scripts. So if you want your script to be executable, use chmod +x your-script.py, then you can use./your-script.py to execute it (as you'll see in this article)

Explore the Platform Module

The platform module is in the standard library, and it has a lot of functions that run our access to many system information. Let's run the Python interpreter to explore some of these functions, starting with the Platform.uname () function:
Copy the Code code as follows:


>>> Import Platform
>>> Platform.uname ()
(' Linux ', ' fedora.echorand ', ' 3.7.4-204.fc18.x86_64 ', ' #1 SMP Wed Jan 16:44:29 UTC ', ' x86_64 ')

If you already know the uname command on Linux, you will recognize that this function is an interface to this command. On Python 2, it returns a system type (or kernel version), host name, version, release version, machine hardware, and processor information tuple (tuple). You can use the subscript to access individual properties like this:
Copy the Code code as follows:


>>> platform.uname () [0]
' Linux '


On Python 3, this function returns a named tuple:
Copy CodeThe code is as follows:


>>> Platform.uname ()

Uname_result (system= ' Linux ', node= ' Fedora.echorand ',
Release= ' 3.7.4-204.fc18.x86_64 ', version= ' #1 SMP Wed Jan 23 16:44:29
UTC ', machine= ' x86_64 ', processor= ' x86_64 ')

Because the returned result is a named tuple, you can simply specify a specific property by its name, rather than having to remember the subscript, like this:
Copy the Code code as follows:


>>> platform.uname (). System
' Linux '

The Platform module also has a direct interface to the above properties, like this:

Copy the Code code as follows:


>>> Platform.system ()
' Linux '

>>> Platform.release ()
' 3.7.4-204.fc18.x86_64 '

The Linux_distribution () function returns details about the release of Linux that you are on. For example, on a Fedora 18 system, this command returns the following information:
Copy the Code code as follows:


>>> platform.linux_distribution ()
(' Fedora ', ' spherical ', ' Cow ')

The return result contains the version release name, version, and the symbol tuple. The published version supported by the specific Python version can be obtained by _supported_dists the value displayed.
Copy the Code code as follows:


>>> platform._supported_dists
(' SuSE ', ' Debian ', ' fedora ', ' redhat ', ' CentOS ', ' Mandrake ',
' Mandriva ', ' Rocks ', ' slackware ', ' yellowdog ', ' Gentoo ',
' Unitedlinux ', ' turbolinux ')

If your Linux release is not in one of these (or one of the derivative distributions). Then you are likely to call the above function without seeing any useful information.
Platform the last function of the module, we will look at the architecture () function. When you call this function without a parameter, it returns a tuple that contains the number of schema bits and the format of the Python executable, like this:
Copy the Code code as follows:


>>> Platform.architecture ()
(' 64bit ', ' ELF ')

On a 32-bit system, you will see:
Copy the Code code as follows:


>>> Platform.architecture ()
(' 32bit ', ' ELF ')

If you specify anything else on the system that you can perform, you will get similar results, like this:

Copy the Code code as follows:


>>> platform.architecture (executable= '/usr/bin/ls ')
(' 64bit ', ' ELF ')

Encourage exploring the other functions of the Platform module, in addition to these, to find out which version of Python you are running now. If you want to know how this module is getting this information, you can drill down into the lib/platform.py file in the Python source directory.

OS and SYS modules can also obtain some system properties, such as native byte-order. Next, we go beyond the Python standard library module to explore some of the possibilities of accessing information on Linux systems through the proc and Sysfs file systems. Note that access to information through the file system will vary from one hardware architecture to another. So when you read this or write a script, always remember that you can try to get information from these files.

Get CPU Information

The/proc/cpuinfo file contains information about your system's processor unit. For example, here is what the Python version of Linux command Cat/proc/cpuinfo does:
Copy the Code code as follows:


#! /usr/bin/env python
"" Print out The/proc/cpuinfo
File
"""

From __future__ import print_function

With open ('/proc/cpuinfo ') as F:
For line in F:
Print (Line.rstrip (' \ n '))

When you use Python 2 or Python 3 to execute this program, you will see all the/proc/cpuinfo content on the screen (in the above program, the Rstrip () method is used to delete the line break at the end of each line)
The following code lists the patterns that use the Startwith () string method to display your processor unit.
Copy the Code code as follows:


#! /usr/bin/env python

"" Print the model of your
Processing Units

"""

From __future__ import print_function

With open ('/proc/cpuinfo ') as F:
For line in F:
# Ignore The blank line separating the information between
# Details about processing units
If Line.strip ():
If Line.rstrip (' \ n '). StartsWith (' model name '):
Model_name = Line.rstrip (' \ n '). Split (': ') [1]
Print (Model_name)

When you run this program, you should see the schema name of each of your processor units. For example, this is what I see on my computer.

Copy the Code code as follows:


Intel (R) Core (TM) i7-3520m CPU @ 2.90GHz
Intel (R) Core (TM) i7-3520m CPU @ 2.90GHz
Intel (R) Core (TM) i7-3520m CPU @ 2.90GHz
Intel (R) Core (TM) i7-3520m CPU @ 2.90GHz

So far, we've had two ways to figure out the architecture of the system we're using. Technically correct, two ways of actually reporting the kernel architecture of your system, so if your computer is 64-bit, but it is running a 32-bit kernel, then the above method will be displayed as a 32-bit schema. You can find the true architecture of your computer by looking for the LM flag from the/proc/cpuinfo list of flags. The LM flag represents a long mode, and only 64-bit architectures will display it. The following program will guide you on how to do it:
Copy the Code code as follows:


#! /usr/bin/env python

"" "Find the Real bit architecture
"""

From __future__ import print_function

With open ('/proc/cpuinfo ') as F:
For line in F:
# Ignore The blank line separating the information between
# Details about processing units
If Line.strip ():
If Line.rstrip (' \ n '). StartsWith (' flags ') \
or Line.rstrip (' \ n '). StartsWith (' Features '):
If ' LM ' in Line.rstrip (' \ n '). Split ():
Print (' 64-bit ')
Else
Print (' 32-bit ')

As we have seen, it is possible to read the/proc/cpuinfo file and use simple text processing techniques to get the data we are looking for. In order to better use this data for other programs, a better idea is to make/proc/cpuinfo content a standard data structure, such as a Dictionary (dictionary). This note is simple: If you look at the contents of this file, you will find that there are a number of key pairs for each processor unit (in the previous example, we have printed the model name of each processor, that is, the model name is the keyword). Information for different processor units can be separated by blank lines. It is very simple to construct a dictionary data structure containing the keywords for each processor unit. For each keyword, the value for the processor unit is in the/proc/cpuinfo file. The following code will guide you on how to do it.
Copy the Code code as follows:


#!/usr/bin/env/python

"""
/proc/cpuinfo as a Python dict
"""
From __future__ import print_function
From collections Import Ordereddict
Import Pprint

Def cpuinfo ():
"Return The information in/proc/cpuinfo
As a dictionary in the following format:
cpu_info[' proc0 ']={...}
cpu_info[' Proc1 ']={...}

'''

Cpuinfo=ordereddict ()
Procinfo=ordereddict ()

Nprocs = 0
With open ('/proc/cpuinfo ') as F:
For line in F:
If not Line.strip ():
# End of one processor
cpuinfo[' proc%s '% nprocs] = ProcInfo
Nprocs=nprocs+1
# Reset
Procinfo=ordereddict ()
Else
If Len (Line.split (': ')) = = 2:
Procinfo[line.split (': ') [0].strip ()] = Line.split (': ') [1].strip ()
Else
Procinfo[line.split (': ') [0].strip ()] = "

Return Cpuinfo

If __name__== ' __main__ ':
Cpuinfo = Cpuinfo ()
For processor in Cpuinfo.keys ():
Print (cpuinfo[processor][' model name ')

This code uses a ordereddict (ordered dictionary) instead of a regular dictionary, which can be stored in a file in an orderly manner using key values. Therefore, the data for the first processor unit is followed by the data of the second processor unit, and so on. You can use filters to filter the information you are looking for (as demonstrated in the IF __name__ = = ' __main__ ' block). Each execution of the above program prints the model name of each processor unit (as indicated by the cpuinfo[processor][' model name '] statement)
Copy the Code code as follows:


Intel (R) Core (TM) i7-3520m CPU @ 2.90GHz
Intel (R) Core (TM) i7-3520m CPU @ 2.90GHz
Intel (R) Core (TM) i7-3520m CPU @ 2.90GHz
Intel (R) Core (TM) i7-3520m CPU @ 2.90GHz

Get memory information

Similar to/proc/cpuinfo, the file/proc/meminfo contains information about the main memory of your computer. The following program creates a dictionary populated with the contents of this file.

Copy the Code code as follows:


#!/usr/bin/env python

From __future__ import print_function
From collections Import Ordereddict

Def meminfo ():
"Return The information in/proc/meminfo
As a dictionary ' '
Meminfo=ordereddict ()

With open ('/proc/meminfo ') as F:
For line in F:
Meminfo[line.split (': ') [0]] = line.split (': ') [1].strip ()
Return Meminfo

If __name__== ' __main__ ':
#print (Meminfo ())

Meminfo = Meminfo ()
Print (' Total memory: {0} '. Format (meminfo[' Memtotal '))
Print (' free memory: {0} '. Format (meminfo[' Memfree '))


Like the previous, through its keywords, you can access any of the specified information you query (indicated in the If __name__==__main__ block). When you execute this program, you should see output similar to the following:

Copy the Code code as follows:


Total memory:7897012 KB
Free memory:249508 KB

Network statistics information

Next, we will explore the network equipment of our computer system. We will have access to the system's network interfaces and the information that sends and receives data through their data after the system restarts. The/proc/net/dev file makes this information available. If you check the contents of this file, you will notice that the head one or two line contains header information and so on, the first column of this file is the network interface name, the second and third columns show the number of bytes received and sent information (such as the total number of bytes sent, the number of packets, errors, etc.). What we're interested in here is that he's sad. Different network devices extract the total sent data and receive data. The following code shows how to extract this information from the/proc/net/dev file.
Copy the Code code as follows:


#!/usr/bin/env python
From __future__ import print_function
From collections Import Namedtuple

Def Netdevs ():
' RX and TX bytes for each of the network devices '

With open ('/proc/net/dev ') as F:
Net_dump = F.readlines ()

device_data={}
data = namedtuple (' Data ', [' Rx ', ' TX '])
For line in Net_dump[2:]:
line = Line.split (': ')
If Line[0].strip ()! = ' lo ':
Device_data[line[0].strip ()] = data (float (line[1].split () [0])/(1024.0*1024.0),
Float (Line[1].split () [8])/(1024.0*1024.0))

Return Device_data

If __name__== ' __main__ ':

Netdevs = Netdevs ()
For Dev in Netdevs.keys ():
Print (' {0}: {1} MIB {2} MIB '. Format (Dev, Netdevs[dev].rx, netdevs[dev].tx))

When you run the above program, the output below shows the total amount of data received and sent from the network device after your most recent reboot, in megabytes.

Copy the Code code as follows:


em1:0.0 MIB 0.0 MIB
wlan0:2651.40951061 MIB 183.173976898 MIB

You can use a persistent data storage mechanism to connect and write your own data usage monitoring program.

Process information

The/proc directory contains all the running process directories. The names of these directories are the same as the process identifiers. So, if you traverse the directories in the/proc directory that use numbers as their names, you get a list of all the processes that are now running. In the following code, the Process_list () function returns a list of all the identifiers of the processes that are now running. When you execute this program, the length of the list is the total number of processes running on the system.
Copy the Code code as follows:


#!/usr/bin/env python
"""
List of all process IDs currently active
"""

From __future__ import print_function
Import OS
Def process_list ():

PIDs = []
For subdir in Os.listdir ('/proc '):
If Subdir.isdigit ():
Pids.append (SubDir)

Return PIDs


If __name__== ' __main__ ':

PIDs = Process_list ()
Print (' Total number of running processes:: {0} '. Format (len (PIDs)))

The above program displays output similar to the following when executed:
Copy the Code code as follows:

Total number of running processes:: 229


Each process directory contains a number of other files and directories, such as calls to process commands, shared libraries It is using, and others.

Block devices

The next program lists all the block devices by reading the SYSFS virtual file system. The block devices in your system can be found in the/sys/block directory. Therefore, there may be/SYS/BLOCK/SDA,/sys/block/sdb and so on such a directory. To get all of these devices, we use regular expressions to scan the/sys/block directory for the block device of interest.

Copy the Code code as follows:


#!/usr/bin/env python

"""
Read block device data from SYSFS
"""

From __future__ import print_function
Import Glob
Import re
Import OS

# ADD Any other device pattern to the read from
Dev_pattern = [' sd.* ', ' mmcblk* ']

def size (device):
nr_sectors = open (device+ '/size '). Read (). Rstrip (' \ n ')
sect_size = open (device+ '/queue/hw_sector_size '). Read (). Rstrip (' \ n ')

# The Sect_size is in bytes, so we convert it to GiB and then send it back
Return (float (nr_sectors) *float (sect_size))/(1024.0*1024.0*1024.0)

Def Detect_devs ():
For device in Glob.glob ('/sys/block/* '):
For pattern in Dev_pattern:
If Re.compile (pattern). Match (Os.path.basename (device)):
Print (' device:: {0}, Size:: {1} GiB '. Format (device, size (device))

If __name__== ' __main__ ':
Detect_devs ()

If you run the program, you will see a similar output as follows:

Copy the Code code as follows:


Device::/sys/block/sda, Size:: 465.761741638 GiB
Device::/sys/block/mmcblk0, Size:: 3.70703125 GiB

When I run the program, there is an SD memory card plugged into the computer, so you will see it detected by the program. You can also extend the program to identify other block devices (such as virtual hard disks).

Creating a command-line utility

Command-line tools are ubiquitous in Linux [@Lesus Note: It has been said that Linux does not have a command line is a slag. ], which allows a person to specify command-line arguments to customize the program's default behavior. The Argparse module provides an interface similar to the Linux command-line utility. The following code shows how the program obtains all the users on the system and the login shell that prints them (using the PWD standard library module):
Copy the Code code as follows:


#!/usr/bin/env python

"""
Print all the users and their login shells
"""

From __future__ import print_function
Import pwd


# Get the Users from/etc/passwd
Def getusers ():
Users = Pwd.getpwall ()
For user in Users:
Print (' {0}:{1} '. Format (User.pw_name, User.pw_shell))

If __name__== ' __main__ ':
Getusers ()

After running this program, it will print all the users on the system and their login shell name.
Now, you want the user of the program to be able to choose whether to look at the system user (like Daemon, Apache). We extend the previous code and use the Argparse module for the first time to implement this feature, as follows.

Copy the Code code as follows:


#!/usr/bin/env python

"""
Utility to play around with users and passwords on a Linux system
"""

From __future__ import print_function
Import pwd
Import Argparse
Import OS

Def read_login_defs ():

Uid_min = None
Uid_max = None

If Os.path.exists ('/etc/login.defs '):
With open ('/etc/login.defs ') as F:
Login_data = F.readlines ()

For line in Login_data:
If Line.startswith (' Uid_min '):
uid_min = Int (Line.split () [1].strip ())

If Line.startswith (' Uid_max '):
Uid_max = Int (Line.split () [1].strip ())

Return Uid_min, Uid_max

# Get the Users from/etc/passwd
def getusers (No_system=false):

Uid_min, Uid_max = Read_login_defs ()

If Uid_min is None:
Uid_min = 1000
If Uid_max is None:
Uid_max = 60000

Users = Pwd.getpwall ()
For user in Users:
If No_system:
If User.pw_uid >= uid_min and User.pw_uid <= Uid_max:
Print (' {0}:{1} '. Format (User.pw_name, User.pw_shell))
Else
Print (' {0}:{1} '. Format (User.pw_name, User.pw_shell))

If __name__== ' __main__ ':

Parser = Argparse. Argumentparser (description= ' User/password Utility ')

Parser.add_argument ('--no-system ', action= ' store_true ', dest= ' No_system ',
Default = False, help= ' Specify to omit system users ')

args = Parser.parse_args ()
Getusers (Args.no_system)

Using the--HELP option to execute the above program, you will see friendly help information: options and their role.

Copy the Code code as follows:


$./getusers.py--help
usage:getusers.py [-h] [--no-system]

User/password Utility

Optional arguments:
-H,--help show this help message and exit
--no-system specify to omit system users

An example used by the above program is as follows:

Copy the Code code as follows:


$./getusers.py--no-system
Gene:/bin/bash

When you pass in an illegal argument, the program will whine (error)
Copy the Code code as follows:


$./getusers.py--param
usage:getusers.py [-h] [--no-system]
getusers.py:error:unrecognized arguments:--param

In the above program, we have a simple understanding of how to use the Argparse module. Parser = Argparse. The Argumentparser (description= "User/password Utility") statement creates a Argumentparser object with an optional description of what the program does,
We then add the parameters. We want the program to be able to recognize the next Statement add_argument ().

Parser.add_argument ('--no-system ', action= ' store_true ', dest= ' no_system ', default = False, help= ' Specify to omit system Users '). The parameter of the first method is when the system calls the program, the program uses the name that will provide the parameter, and the next parameter, Acton=store_true, indicates that it is a Boolean selection. That is to say, it really or falsely affects certain behavior of the program. Dest is a customizable parameter, and its value can be provided to the program for use. If this value is not provided by the user, this value defaults to False. The final parameter program displays the Help information. Finally, the parameters are parsed through the Args=parser.parse_args () method. Once the parsing method is done, the value of the user option can be crawled to the corresponding syntax parameter option_dest, when you configure the parameters, Option_dest is a target variable that you specify. Getusers (Args.no_system) This statement uses the value of the user-supplied parameter to callback the Getusers () method.

The following program shows how to specify options for non-Boolean types. The program is a rewrite of the 6th program, with an option to specify which network devices you are interested in.
Copy the Code code as follows:


#!/usr/bin/env python
From __future__ import print_function
From collections Import Namedtuple
Import Argparse

def Netdevs (Iface=none):
' RX and TX bytes for each of the network devices '

With open ('/proc/net/dev ') as F:
Net_dump = F.readlines ()

device_data={}
data = namedtuple (' Data ', [' Rx ', ' TX '])
For line in Net_dump[2:]:
line = Line.split (': ')
If not iface:
If Line[0].strip ()! = ' lo ':
Device_data[line[0].strip ()] = data (float (line[1].split () [0])/(1024.0*1024.0),
Float (Line[1].split () [8])/(1024.0*1024.0))
Else
If Line[0].strip () = = Iface:
Device_data[line[0].strip ()] = data (float (line[1].split () [0])/(1024.0*1024.0),
Float (Line[1].split () [8])/(1024.0*1024.0))
Return Device_data

If __name__== ' __main__ ':

Parser = Argparse. Argumentparser (description= ' Network Interface Usage Monitor ')
Parser.add_argument ('-I ', '--interface ', dest= ' iface ',
help= ' Network interface ')

args = Parser.parse_args ()

Netdevs = Netdevs (iface = args.iface)
For Dev in Netdevs.keys ():
Print (' {0}: {1} MIB {2} MIB '. Format (Dev, Netdevs[dev].rx, netdevs[dev].tx))


When you execute the program without any parameters, the program behaves exactly like the previous version. You can then specify the network devices that you are interested in. For example:

Copy the Code code as follows:


$./net_devs_2.py

em1:0.0 MIB 0.0 MIB
wlan0:146.099492073 MIB 12.9737148285 MIB
virbr1:0.0 MIB 0.0 MIB
virbr1-nic:0.0 MIB 0.0 MIB

$./net_devs_2.py--help
usage:net_devs_2.py [-h] [-I IFACE]

Network Interface Usage Monitor

Optional arguments:
-H,--help show this help message and exit
-I IFACE,--interface IFACE
Network interface

$./net_devs_2.py-i Wlan0
wlan0:146.100307465 MIB 12.9777050018 MIB

System-wide availability of scripts

With the help of this article, you may already be able to write one or more useful scripts, just like any other Linux command, and you want to use them every day. The simplest way is to set the script to executable and then set a bash alias for the script. You can also remove the. py extension, and then place the script in a standard location such as/usr/local/sbin.

Other useful standard library modules

In addition to the standard library modules already mentioned in this article, there are many other useful standard modules: subprocess, Configparser, ReadLine, and curses.

What do you do next?

At this stage, depending on your own experience with Python, explore Linux inside, you can refer to any of the following ways. If you ever need to write a lot of shell scripts/command lines to explore Linux inside, then try Python. If you want a simpler way to write utility scripts that perform many tasks, try Python. Finally, if you've already used Python to write other programs on Linux, try using Python to explore Linux inside.

  • Related Article

    Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.