Learn Python Control Flow and Loops to Write and Tune Shell Scripts – Part 2

Python Script

It is considered good practice to start a script with a statement that indicates the purpose of the script, the license terms under which it is released, and a revision history listing the changes that have been made. Although this is more of a personal preference, it adds a professional touch to our work.

Here’s the script that produces the output we shown at the top of this article. It is heavily commented so that you can understand what’s happening.

Take a few minutes to go through it before proceeding. Note how we use an if / else structure to determine whether the length of each field caption is greater than the value of the field itself.

Based on the result, we use empty characters to fill in the space between a field caption and the next. Also, we use the right number of dashes as separator between the field caption and its value below.

#!/usr/bin/python3
# Change the above line to #!/usr/bin/python if you don't have Python 3 installed

# Script name: uname.py
# Purpose: Illustrate Python's OOP capabilities to write shell scripts more easily
# License: GPL v3 (http://www.gnu.org/licenses/gpl.html)

# Copyright (C) 2016 Gabriel Alejandro Cánepa
# ​Facebook / Skype / G+ / Twitter / Github: gacanepa
# Email: gacanepa (at) gmail (dot) com

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

# REVISION HISTORY
# DATE   	  VERSION AUTHOR    	 CHANGE DESCRIPTION
# ---------- ------- --------------
# 2016-05-28 1.0     Gabriel Cánepa    Initial version

# Import the os module
import os

# Assign the output of os.uname() to the the systemInfo variable
# os.uname() returns a 5-string tuple (sysname, nodename, release, version, machine)
# Documentation: https://docs.python.org/3.2/library/os.html#module-os
systemInfo = os.uname()

# This is a fixed array with the desired captions in the script output
headers = ["Operating system","Hostname","Release","Version","Machine"]

# Initial value of the index variable. It is used to define the
# index of both systemInfo and headers in each step of the iteration.
index = 0

# Initial value of the caption variable.
caption = ""

# Initial value of the values variable
values = ""

# Initial value of the separators variable
separators = ""

# Start of the loop
for item in systemInfo:
    if len(item) < len(headers[index]):
   	 # A string containing dashes to the length of item[index] or headers[index]
   	 # To repeat a character(s), enclose it within quotes followed
   	 # by the star sign (*) and the desired number of times.
   	 separators = separators + "-" * len(headers[index]) + " "
   	 caption = caption + headers[index] + " "
   	 values = values + systemInfo[index] + " " * (len(headers[index]) - len(item)) + " "
    else:
   	 separators = separators + "-" * len(item) + " "
   	 caption =  caption + headers[index] + " " * (len(item) - len(headers[index]) + 1)
   	 values = values + item + " "
    # Increment the value of index by 1
    index = index + 1
# End of the loop

# Print the variable named caption converted to uppercase
print(caption.upper())

# Print separators
print(separators)

# Print values (items in systemInfo)
print(values)

# INSTRUCTIONS:
# 1) Save the script as uname.py (or another name of your choosing) and give it execute permissions:
# chmod +x uname.py
# 2) Execute it:
# ./uname.py

Once you have saved the above script to a file, give it execute permissions and run it as indicated at the bottom of the code:

# chmod +x uname.py
# ./uname.py

If you get the following error while attempting to execute the script:

-bash: ./uname.py: /usr/bin/python3: bad interpreter: No such file or directory

It means you don’t have Python 3 installed. If that is the case, you can either install the package or replace the interpreter line (pay special attention and be very careful if you followed the steps to update the symbolic links to the Python binaries as outlined in the previous article):

#!/usr/bin/python3

with

#!/usr/bin/python

which will cause the installed version of Python 2 to execute the script instead.

Note: This script has been tested successfully both in Python 2.x and 3.x.

Although somewhat rudimentary, you can think of this script as a Python module. This means that you can open it in the IDLE (File → Open… → Select file):

Open Python in IDLE
Open Python in IDLE

A new window will open with the contents of the file. Then go to Run → Run module (or just press F5). The output of the script will be shown in the original shell:

Run Python Script
Run Python Script

If you want to obtain the same results with a script written purely in Bash, you would need to use a combination of awk, sed, and resort to complex methods to store and retrieve items in a list (not to mention the use of tr to convert lowercase letters to uppercase).

In addition, Python provides portability in that all Linux systems ship with at least one Python version (either 2.x or 3.x, sometimes both). Should you need to rely on a shell to accomplish the same goal, you would need to write different versions of the script based on the shell.

This goes to show that Object Oriented Programming features can become strong allies of system administrators.

Note: You can find this python script (and others) in one of my GitHub repositories.

Summary

In this article we have reviewed the concepts of control flow, loops / iteration, and modules in Python. We have shown how to leverage OOP methods and properties in Python to simplify otherwise complex shell scripts.

Do you have any other ideas you would like to test? Go ahead and write your own Python scripts and let us know if you have any questions. Don’t hesitate to drop us a line using the comment form below, and we will get back to you as soon as we can.

If you liked this article, then do subscribe to email alerts for Linux tutorials. If you have any questions or doubts? do ask for help in the comments section.

If You Appreciate What We Do Here On TecMint, You Should Consider:

TecMint is the fastest growing and most trusted community site for any kind of Linux Articles, Guides and Books on the web. Millions of people visit TecMint! to search or browse the thousands of published articles available FREELY to all.

If you like what you are reading, please consider buying us a coffee ( or 2 ) as a token of appreciation.

Support Us

We are thankful for your never ending support.

7 thoughts on “Learn Python Control Flow and Loops to Write and Tune Shell Scripts – Part 2”

  1. Gabriel,

    Don’t get why this script isn’t working, even after correcting for indentation and adding utf-8 it only runs under IDE’s.

    At the console I still get…..

    ./uname.py: line 1: #!/usr/bin/python: No such file or directory
    

    I only code in 2.7 hence the change or omission of line one. I Chmod it and that is the correct path to python2.7.
    Yet this is the only python file run at the console that complains like this……….?

    Reply
  2. The web version does not include indentation where required by python syntax. I added the indentation and got past those errors and then got
    the following:

    SyntaxError: Non-ASCII character ‘\xc3’ in file uname.py on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details

    Also it will not run on windows because os.uname not available except on linux.

    I got around these errors by using pythonanywhere.com on the web. It ran and was neat but I would think some one at tecmint could help with
    the indentation problem and also specify it will not work on Windows.

    Reply
    • @Paul,
      Thanks for bringing this to our attention. I must confess I never thought I had to state explicitly this would work on Linux only, but we will add that notice as per your suggestion.
      @Ravi,
      Please add a small note to clarify. As for the indentation, perhaps we will need a different WP plugin. Any ideas?

      Reply
    • @big joe,
      It’s possible that the web formatting has damaged the indentation a little. But I can assure you that the program works, as you can see in the screenshots.

      Reply
  3. I prefer to use subprocess.Popen to execute Linux commands:
    uptime = subprocess.Popen([‘uptime’, ‘-s’], stdout=subprocess.PIPE).communicate()[0]

    I would also recommend O’Reilly’s “Python for Unix and Linux System Administration”, by Noah Gift & Jeremy Jones. You can easily find .pdfs (if you don’t want to buy it).

    Reply
    • @Andy,
      While that is true, on a personal note I prefer to keep things as simple as possible. If there is a Python-native way of executing a given command without spawning new process, I’d usually stick with it. Thank you for the book recommendation, I’ll take a look at it.

      Reply

Got something to say? Join the discussion.

Have a question or suggestion? Please leave a comment to start the discussion. Please keep in mind that all comments are moderated and your email address will NOT be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.