sahli.net

Bash vs. Python

Consider this when writing Scripts

SysAdmin or DevOps Engineers have to deal every day with scripts. Before choosing the language we should consider some points. Depending of the use case a Bash script is better than a Python Script/Program and vice versa.

Error Handling

Except and handle Errors

When writing any kind of software the developer needs to think where and which error could happen and how it can be handled. Sometimes errors are expected, sometimes they just happen.
¨

Bash

In Bash scripts typical errors must be handled.

Calling an external program exits with a non-zero return code
an expected resource does not exist (file, socket)
A safe way is to use set -e:

Exit immediately if a simple command exits with a non-zero status.

That means, if for example the script needs to unarchive a tar-file but the file is corrupt and tar exits with code 2, then the script stops.

Sometimes it is difficult to comprehend were the error happened. In this situations set -x helps to increase the output. Also when running the script as cronjob the output should include the verbose output for later analysis.

Python

In Python exceptions are handled with the try, except, else, finally statements. If an exception is not handled the script exits throwing the exception. The traceback in the output tells were the error happened.

Testing your program

Keep good quality

Scripts must be treaded like any other peace of software. To be sure that our software behaves as expected software developers write Unittest's to test small pieces of functionalities. Sometimes even the developer writes the tests after he receives the requirements and then starts writing the software until every test runs successfull.

The same we can do with Python Scripts. We could use a heavy unittest framework or doctest, which is great for testing scripts in a simple manner.

#!/usr/bin/env python
"""
This implements a function which prefixes a string with `a-`.
>>> a("beer")
a-b
"""

Then we run the test and we expect, that the test fails because we didn't implement the function a yet.

$ python -m doctest -v a.py
Trying:
    a("beer")
Expecting:
    a-b
**********************************************************************
File "a.py", line 3, in a
Failed example:
    a("beer")
Expected:
    a-b
Got:
    beer
1 items had no tests:
    a.a
**********************************************************************
1 items had failures:
1 of   1 in a
1 tests in 2 items.
0 passed and 1 failed.
***Test Failed*** 1 failures.
(tumbo) Philips-iMac:plone fatrix$ vi a.py
(tumbo) Philips-iMac:plone fatrix$ python -m doctest -v a.py
Trying:
    a("beer")
Expecting:
    a-b
**********************************************************************
File "a.py", line 3, in a
Failed example:
    a("beer")
Exception raised:
    Traceback (most recent call last):
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/doctest.py", line 1315, in __run
        compileflags, 1) in test.globs
    File "<doctest a[0]>", line 1, in <module>
        a("beer")
    NameError: name 'a' is not defined
**********************************************************************
1 items had failures:
1 of   1 in a
1 tests in 1 items.
0 passed and 1 failed.
***Test Failed*** 1 failures.

Now we implement the script.

#!/usr/bin/env python
"""
>>> a("beer")
a-beer
"""

def a(b):
    print("a-{}".format(b))
Run the test again:

$ python -m doctest -v a.py
Trying:
    a("beer")
Expecting:
    a-beer
ok
1 items had no tests:
    a.a
1 items passed all tests:
1 tests in a
1 tests in 2 items.
1 passed and 0 failed.
Test passed.

Script Arguments

Make it simple

Often a script needs to take input parameters and the person running the script needs to know how to execute it. Therefore we need to configure arguments and give a help output in the cases:

  • script is called with the option -h or --help
  • script is called with wrong arguments

docopt for Python scripts takes all at one place - the declaration of the arguments is already the help text. This makes it easier to implement and with less code.

Conclusion

In both options it is possible to create maintainable and robust scripts. The choice is up to the author (and the later maintainer) of the script, in which language he/she feels familiar.

The key is the concept about exception handling, argument parsing and automated testing.

blog comments powered by Disqus