Python-Linux Shell Scripting: Best Practices

Charles Mwaniki
16 min readApr 12, 2023

--

Python Linux Bash Scripting

Python-Linux shell scripting is a powerful tool that allows you to automate tasks on your Linux system using the Python programming language. Here are some best practices that will help you write effective and efficient Python-Linux shell scripts:

  1. Use a shebang line

The shebang line is the first line of your Python-Linux shell script and specifies the interpreter that should be used to run the script. The shebang line is essential as it ensures that the script runs with the correct interpreter and is a critical part of any Python-Linux shell script.

The shebang line starts with #! followed by the path to the interpreter. For Python scripts, the path is usually: #!/usr/bin/env python or #!/usr/bin/python. The env command searches the PATH for the python executable, which makes your script more portable and avoids hard-coding the path to the Python interpreter.

Here are some tips for using a shebang line:

  1. Always include a shebang line at the beginning of your script.
  2. Use the env command to locate the Python interpreter, as this avoids hard-coding the path to the interpreter.
  3. Specify the full path to the interpreter if the env command is not available or not suitable.
  4. Make sure the interpreter specified in the shebang line is installed on the system where the script will be run.
  5. Use the appropriate version of Python for your script, as different versions of Python may have different syntax or behavior.
  6. Avoid using spaces in the shebang line, as some systems may not handle them correctly.

By including a shebang line in your Python-Linux shell script, you ensure that the script is executed with the correct interpreter, making your script more portable and easier to run on different systems.

2. Use descriptive variable names

Using descriptive variable names is an essential best practice for Python-Linux shell scripting. Descriptive variable names make your code more readable and easier to understand, both for yourself and for other developers who may need to maintain or modify your code in the future. Here are some tips for using descriptive variable names in your Python-Linux shell scripts:

  1. Use meaningful names: Choose variable names that accurately describe the value they hold. Avoid using generic or abbreviated names, as they may not provide enough context for other developers to understand what the variable represents.
  2. Use underscores: Use underscores to separate words in variable names, as this makes them more readable. For example, use file_path instead of filePath or filepath.
  3. Use camel case: Use camel case for function names, as this is a common convention in Python. For example, use openFile instead of open_file or openfile.
  4. Use constants: Use constants for values that do not change throughout the script. Constants should be in all caps, with words separated by underscores. For example, MAX_RETRIES or DEFAULT_PORT.
  5. Avoid single-letter variable names: Avoid using single-letter variable names, except for commonly used names such as i, j, or k in loops. Single-letter variable names do not provide enough context and can be confusing.
  6. Be consistent: Use consistent naming conventions throughout your script. This makes your code more readable and easier to understand.
import os

# Define the path to the input file
input_file_path = os.path.join(os.getcwd(), 'input.txt')

# Define the path to the output file
output_file_path = os.path.join(os.getcwd(), 'output.txt')

# Define the maximum number of retries
MAX_RETRIES = 3

# Define the default port number
DEFAULT_PORT = 8080

# Define a function to open a file and return its contents
def read_file(file_path):
with open(file_path, 'r') as f:
contents = f.read()
return contents

By using descriptive variable names, you make your Python-Linux shell scripts more readable, understandable, and maintainable, which helps you and other developers work with your code more efficiently.

3. Use comments

Comments help to explain what your code does, how it works, and why certain decisions were made. Comments make your code more readable and understandable, both for yourself and for other developers who may need to maintain or modify your code in the future.

Unlock the power of Python-Linux Shell Scripting with my comprehensive guide! Dive deeper into automation techniques and system administration tasks with practical examples. Grab your copy of “Python-Linux Shell Scripting: Automating System Administration Tasks” on Amazon today!

Here are some tips for using comments in your Python-Linux shell scripts:

  1. Use comments to explain the purpose of the script: The first few lines of your script should include comments that explain what the script does, how to run it, and any important considerations or assumptions.
  2. Use comments to explain each section of the script: Use comments to explain what each section of your code does and how it contributes to the overall functionality of the script. This makes your code more understandable, especially for people who may not be familiar with the specific implementation details.
  3. Use comments to explain complex or tricky code: If you have complex or tricky code, use comments to explain what it does and why it works that way. This helps other developers understand how the code works and can save them time when trying to modify or debug it.
  4. Use comments to document functions: Use comments to document the inputs, outputs, and purpose of each function in your script. This makes it easier for other developers to use and modify your code.
  5. Be concise and clear: Keep your comments concise and clear. Use simple language, avoid technical jargon, and make sure your comments accurately reflect the code they are describing.

Here’s an example of using comments in a Python-Linux shell script:

#!/usr/bin/env python

# Script to generate a report of the top 10 most frequent words in a text file
# Usage: ./word_freq_report.py input_file.txt

import sys

# Define the input file path
input_file_path = sys.argv[1]

# Define a function to count the frequency of each word in the file
def count_words(file_path):
# Open the file and read its contents
with open(file_path, 'r') as f:
contents = f.read()

# Split the contents into words and count the frequency of each word
words = contents.split()
word_freq = {}
for word in words:
if word in word_freq:
word_freq[word] += 1
else:
word_freq[word] = 1

return word_freq

# Define a function to generate a report of the top 10 most frequent words
def generate_report(word_freq):
# Sort the word frequency dictionary by value, in descending order
sorted_word_freq = sorted(word_freq.items(), key=lambda x: x[1], reverse=True)

# Print the top 10 most frequent words and their frequencies
print('Word\tFrequency')
for word, freq in sorted_word_freq[:10]:
print(f'{word}\t{freq}')

# Main script execution starts here
if __name__ == '__main__':
# Count the frequency of each word in the input file
word_freq = count_words(input_file_path)

# Generate a report of the top 10 most frequent words
generate_report(word_freq)

Comments make your Python-Linux shell scripts more readable, understandable, and maintainable, which helps you and other developers work with your code more efficiently.

4. Use error handling

Error handling is an essential best practice for Python-Linux shell scripting. When writing scripts, it is important to consider potential errors and handle them in a way that allows the script to gracefully recover or exit. Without error handling, your script may fail unexpectedly and be difficult to debug.

Here are some tips for using error handling in your Python-Linux shell scripts:

  1. Use try-except blocks: Wrap potentially problematic code in a try-except block. This allows you to catch and handle exceptions that may occur during script execution.
  2. Handle specific exceptions: Use specific exception handling to handle only the exceptions you expect to encounter. This allows you to handle exceptions in a more targeted way and avoid unintended consequences.
  3. Provide informative error messages: When an error occurs, provide informative error messages that explain what went wrong and how to fix it. This makes it easier for users to understand and resolve issues that may arise.
  4. Use logging: Use logging to track errors and provide information about what happened during script execution. This helps with debugging and can provide valuable information for troubleshooting.
  5. Consider using a try-finally block: Use a try-finally block to ensure that critical resources are released, even if an exception occurs. For example, if your script opens a file, use a try-finally block to ensure that the file is closed, even if an exception occurs.

Here’s an example of using error handling in a Python-Linux shell script:

#!/usr/bin/env python

import sys

# Define the input file path
try:
input_file_path = sys.argv[1]
except IndexError:
print("Error: No input file specified. Usage: ./script.py input_file.txt")
sys.exit(1)

# Define a function to count the frequency of each word in the file
def count_words(file_path):
try:
# Open the file and read its contents
with open(file_path, 'r') as f:
contents = f.read()

# Split the contents into words and count the frequency of each word
words = contents.split()
word_freq = {}
for word in words:
if word in word_freq:
word_freq[word] += 1
else:
word_freq[word] = 1

return word_freq
except FileNotFoundError:
print(f"Error: Input file '{file_path}' not found.")
sys.exit(1)

# Define a function to generate a report of the top 10 most frequent words
def generate_report(word_freq):
# Sort the word frequency dictionary by value, in descending order
sorted_word_freq = sorted(word_freq.items(), key=lambda x: x[1], reverse=True)

# Print the top 10 most frequent words and their frequencies
print('Word\tFrequency')
for word, freq in sorted_word_freq[:10]:
print(f'{word}\t{freq}')

# Main script execution starts here
if __name__ == '__main__':
# Count the frequency of each word in the input file
word_freq = count_words(input_file_path)

# Generate a report of the top 10 most frequent words
generate_report(word_freq)

In this example, the script checks that an input file is specified, handles a FileNotFoundError if the file is not found, and provides an informative error message. By using error handling, you make your Python-Linux shell scripts more reliable and robust, which helps you and other developers work with your code more efficiently.

5. Use functions

Functions are a way to break up your code into smaller, more manageable pieces. Use functions to encapsulate a set of related tasks, making your code more modular and easier to maintain.

Using functions is an important best practice for Python-Linux shell scripting. Functions allow you to organize your code into reusable pieces, which can make your scripts more modular, easier to read, and easier to maintain. Functions can also make it easier to test and debug your scripts.

Here are some tips for using functions in your Python-Linux shell scripts:

  1. Define clear and concise function names: Choose function names that are clear and concise, and describe what the function does. Use lowercase letters and underscores to separate words in function names.
  2. Use function arguments: Use function arguments to pass data into your functions. This makes your code more modular and allows you to reuse your functions with different inputs.
  3. Use return values: Use return values to return data from your functions. This makes it easier to work with the data that your functions produce.
  4. Keep functions short and focused: Keep your functions short and focused, with a single responsibility. This makes your code easier to read and understand and helps you avoid bugs.
  5. Avoid global variables: Avoid using global variables in your functions, as they can make it harder to reason about your code and make it harder to test and debug.

Here’s an example of using functions in a Python-Linux shell script:

#!/usr/bin/env python

import sys

# Define a function to count the frequency of each word in a file
def count_words(file_path):
try:
# Open the file and read its contents
with open(file_path, 'r') as f:
contents = f.read()

# Split the contents into words and count the frequency of each word
words = contents.split()
word_freq = {}
for word in words:
if word in word_freq:
word_freq[word] += 1
else:
word_freq[word] = 1

return word_freq
except FileNotFoundError:
print(f"Error: Input file '{file_path}' not found.")
sys.exit(1)

# Define a function to generate a report of the top 10 most frequent words
def generate_report(word_freq):
# Sort the word frequency dictionary by value, in descending order
sorted_word_freq = sorted(word_freq.items(), key=lambda x: x[1], reverse=True)

# Print the top 10 most frequent words and their frequencies
print('Word\tFrequency')
for word, freq in sorted_word_freq[:10]:
print(f'{word}\t{freq}')

# Main script execution starts here
if __name__ == '__main__':
# Define the input file path
try:
input_file_path = sys.argv[1]
except IndexError:
print("Error: No input file specified. Usage: ./script.py input_file.txt")
sys.exit(1)

# Count the frequency of each word in the input file
word_freq = count_words(input_file_path)

# Generate a report of the top 10 most frequent words
generate_report(word_freq)

In this example, the script uses two functions to count the frequency of each word in a file and generate a report of the top 10 most frequent words. By using functions, the code is more modular and easier to read and understand.

6. Use command-line arguments:

Using command-line arguments is an important best practice for Python-Linux shell scripting. Command line arguments allow users to provide input to your script without having to modify the script itself. They also make your scripts more flexible and reusable.

Here are some tips for using command line arguments in your Python-Linux shell scripts:

  1. Use the argparse module: The argparse module provides a convenient way to parse command line arguments. It allows you to define the arguments your script expects, with optional default values and help messages.
  2. Define clear and concise argument names: Choose argument names that are clear and concise, and describe what the argument represents. Use lowercase letters and underscores to separate words in argument names.
  3. Use optional and positional arguments: Use optional arguments for arguments that have default values, and positional arguments for required arguments.
  4. Handle invalid arguments gracefully: If a user provides an invalid argument or value, handle the error gracefully and provide a helpful error message.
  5. Document your script’s usage: Document your script’s usage with a usage statement or help message, so that users know how to run your script and what arguments are available.

Here’s an example of using command-line arguments in a Python-Linux shell script:

#!/usr/bin/env python

import argparse

# Define command line arguments
parser = argparse.ArgumentParser(description='Calculate the sum of two numbers.')
parser.add_argument('num1', type=float, help='the first number')
parser.add_argument('num2', type=float, help='the second number')
parser.add_argument('--verbose', action='store_true', help='output the calculation process')

# Define a function to calculate the sum of two numbers
def calculate_sum(num1, num2, verbose=False):
if verbose:
print(f"Calculating the sum of {num1} and {num2}...")
return num1 + num2

# Main script execution starts here
if __name__ == '__main__':
# Parse command line arguments
args = parser.parse_args()

# Calculate the sum of the two numbers
result = calculate_sum(args.num1, args.num2, args.verbose)

# Print the result
print(result)

In this example, the script uses the argparse module to define two required positional arguments (num1 and num2) and one optional flag argument ( — verbose). The script then uses a function to calculate the sum of the two numbers and optionally prints the calculation process if the — verbose flag is provided. Finally, the script prints the result of the calculation.

By using command line arguments, the script is more flexible and reusable and can be easily run with different input values.

7. Use proper indentation

Using proper indentation is an essential best practice for Python-Linux shell scripting. Indentation is used to define the structure and flow of your code, and it can have a significant impact on your code’s readability and maintainability.

Here are some tips for using proper indentation in your Python-Linux shell scripts:

  1. Use four spaces for indentation: The Python community generally agrees that four spaces are the preferred indentation level. You can configure your text editor or IDE to automatically insert four spaces when you press the Tab key.
  2. Use consistent indentation: Use the same indentation level throughout your code, and be consistent with how you indent each block of code. This will make your code easier to read and understand.
  3. Indent code blocks: Indent all lines of code within a code block, such as within a function definition, if statement, for loop, or while loop.
  4. Avoid mixing tabs and spaces: Mixing tabs and spaces for indentation can cause inconsistencies in your code and make it harder to read. Stick to using either tabs or spaces for indentation, and be consistent.
  5. Use indentation to improve readability: Use indentation to group related code together and create a clear visual hierarchy in your code. This will make it easier for others to read and understand your code.

Here’s an example of using proper indentation in a Python-Linux shell script:

#!/usr/bin/env python

# Define a function to print a message with indentation
def print_message(message, level=0):
indent = " " * level
print(f"{indent}{message}")

# Main script execution starts here
if __name__ == '__main__':
# Print a message with level 0 indentation
print_message("Starting script...")

# Loop over a range of numbers and print each number with level 1 indentation
for i in range(5):
print_message(f"Number: {i}", level=1)

# Print a message with level 0 indentation
print_message("Script complete.")

In this example, the script defines a function print_message that takes a message and an optional level argument to specify the indentation level. The function uses the indent variable to calculate the appropriate amount of indentation based on the specified level.

The main script then uses the print_message function to print a message with level 0 indentation, enters a for loop to print each number with level 1 indentation, and finally prints a message with level 0 indentation again.

By using proper indentation, the script is more readable and easier to follow, which can make it easier to maintain and debug in the future.

8. Use file permissions

Use file permissions to restrict access to your script and protect sensitive data. Set appropriate permissions on your script file so that only authorized users can run or modify it.

Setting file permissions is an important best practice for Python-Linux shell scripting to ensure that your scripts are secure and only accessible to the users who need to run them.

Here are some tips for setting file permissions on your Python-Linux shell scripts:

  1. Use chmod command to set file permissions: chmod is a command-line utility that allows you to change the file permissions of a file or directory. It supports three types of permissions: read (r), write (w), and execute (x).
  2. Set appropriate permissions for the owner, group, and others: You can set permissions separately for the owner of the file, the group that owns the file, and other users. Use the following commands to set file permissions for each group:
  • Owner: chmod u+permission filename
  • Group: chmod g+permission filename
  • Others: chmod o+permission filename

Replace permission with r, w, or x to add or remove the respective permission. For example, chmod u+x filename would add executable permission for the file’s owner.

  1. Use octal values to set permissions: You can also use octal values to set file permissions in a more concise way. Each permission (r, w, or x) is assigned a numeric value as follows:
  • r: 4
  • w: 2
  • x: 1

You can add these values together to create a three-digit octal value that represents the file’s permissions. For example, chmod 755 filename would set the file’s permissions to rwxr-xr-x, which means the file’s owner can read, write, and execute it, while other users can only read and execute it.

  1. Use umask to set default file permissions: umask is a command that sets the default file permissions for newly created files and directories. By default, the umask is set to 022, which means that the group and others can’t write to the file or directory. You can use the umask command to set a more restrictive or permissive default permission.

Here’s an example of setting file permissions for a Python-Linux shell script named bashscript.py:

# Set file permissions to 755 (rwxr-xr-x) for the owner and read/execute for group and others
chmod 755 bashscript.py

# Set default file permissions to 700 (rwx------) for newly created files and directories
umask 007

By setting appropriate file permissions, you can ensure that your Python-Linux shell scripts are secure and only accessible to the users who need to run them.

9. Use virtual environments:

Using virtual environments is a crucial best practice for Python-Linux shell scripting. A virtual environment is an isolated environment for Python that allows you to install packages and dependencies without affecting the system-wide Python installation. This is especially important when working on multiple projects with different dependencies.

Here are some tips for using virtual environments in Python-Linux shell scripting:

  1. Install a virtual environment package: There are several virtual environment packages available for Python, including virtualenv and venv. You can install them using the package manager of your Linux distribution or by using pip, the package installer for Python.
  2. Create a new virtual environment: Once you have installed a virtual environment package, you can create a new virtual environment by running the following command:
virtualenv myenv

or

python3 -m venv myenv

This will create a new virtual environment in a directory named myenv in your current working directory.

3. Activate the virtual environment: To start using the virtual environment, you need to activate it. You can do this by running the following command:

source myenv/bin/activate

This will activate the virtual environment and modify your PATH environment variable to include the virtual environment’s bin directory.

4. Install dependencies: Once you have activated the virtual environment, you can install the required packages and dependencies using pip. For example, to install the requests package, you can run the following command:

pip install requests

5. Deactivate the virtual environment: When you are done working in the virtual environment, you can deactivate it by running the following command:

deactivate

This will remove the virtual environment’s bin directory from your PATH environment variable.

Using virtual environments in your Python-Linux shell scripts ensures that your scripts are running with the required dependencies and reduces the risk of conflicts with other system-wide packages.

10. Test your script

Testing your Python-Linux shell scripts is an important best practice to ensure that your code is working as expected and to catch any bugs or issues early in the development process. Here are some tips for testing your scripts:

  1. Use a testing framework: There are several testing frameworks available for Python, including unittest, pytest, and nose. These frameworks provide a structure for writing and running tests, making it easier to catch errors and to maintain and extend your test suite.
  2. Write unit tests: Unit tests are small, isolated tests that verify the behavior of a specific function or module. They are an essential part of testing your code and help ensure that each component is working correctly. Write unit tests for each function or module in your script and ensure that they cover all possible cases.
  3. Test edge cases: Make sure to test edge cases, such as invalid inputs or unexpected outputs, to catch potential issues that may arise in real-world scenarios.
  4. Automate your tests: Running your tests manually can be time-consuming and error-prone. Automate your tests by using a continuous integration (CI) tool like Jenkins, Travis CI, or CircleCI to run your tests automatically whenever you push code changes.
  5. Use code coverage tools: Code coverage tools can help you determine how much of your code is covered by your tests. This information can help you identify areas that need more testing and ensure that you are testing all parts of your code.
  6. Use assert statements: Use assert statements in your tests to verify that your code is producing the expected output. This can help catch errors early and make it easier to diagnose issues.

By testing your Python-Linux shell scripts, you can ensure that your code is working correctly and catch potential issues early in the development process. This can save you time and help you avoid headaches down the road.

In summary, following these best practices will help you write more maintainable, efficient, and error-free Python-Linux shell scripts.

If you’re eager to dive deeper into Python-Linux Shell Scripting and master automation techniques for system administration, check out my book “Python-Linux Shell Scripting: Automating System Administration Tasks” on Amazon. It’s packed with comprehensive guidance and practical examples to level up your skills. Ready to take your expertise to the next level? Grab your copy now!

--

--

Charles Mwaniki

Certified Cloud Practitioner | Software Engineer | Data Analyst