Converting a bash script to python (small script)
Question: I’ve a bash script I’ve been using for a Linux environment but now I have to
use it on a Windows platform and want to convert the bash script to a python
script which I can run.

The bash script is rather simple (I think) and I’ve tried to convert it by
google by way around but can’t convert it successfully.

The bash script looks like this:

    
    
    runs=5
    
    queries=50
    
    outfile=outputfile.txt
    
    date  >> $outfile
    
    
    echo -e "\n---------------------------------"
    echo -e "\n----------- Normal --------------"
    echo -e "\n---------------------------------"
    echo -e "\n----------- Normal --------------" >> $outfile
    for ((r = 1; r < ($runs + 1); r++))
    do
        echo -e "Run $r of $runs\n"
    
        db2 FLUSH PACKAGE CACHE DYNAMIC
    
        python reads.py -r1 -pquery1.sql -q$queries -shotelspec -k6 -a5 >> $outfile
    done
    

The main command, the python read.py … etc. is another python file I’ve been
given and have the arguments as you see.

I know it is a lot to ask for, but it would really help me out if someone
could convert this to a python script I can use or at least give me some hints
and directions.

Sincerely

Mestika

# Added per request:

This is what I've written but without success:

    
    
    runs=5
    queries=50
    outfile=ReadsAgain.txt
    file = open("results.txt", "ab")
    
    print "\n---------------------------------"
    print "\n----------- Normal --------------"
    print "\n---------------------------------"
    file.write("\n----------- Normal --------------\n")
    print "\n------------- Query without Index --------------"
    file.write("\n------------- Query without Index --------------\n")
    for r = 1; r < (%s + 1); r++ % runs
        print "Run %s of %s \n" % r % runs
    
        db2 FLUSH PACKAGE CACHE DYNAMIC
    
        output = python reads.py -r1 -pquery1.sql -q$queries -shotelspec -k6 -a5
        file.write(output)
    
    file.close()
    


Answer: ## Answer

Let's break it down into pieces. Especially the pieces you got wrong. :)

* * *

### Assignment

>
>     outfile=ReadsAgain.txt
>  

It should come to little surprise that you need to put quotes around strings.
On the other hand, you have the luxury of putting spaces around the `=` for
readability.

    
    
    outfilename = "ReadsAgain.txt"
    

* * *

### Variable expansion →
[`str.format`](http://docs.python.org/library/stdtypes.html#str.format) (or,
the [`%`](http://docs.python.org/library/stdtypes.html#string-formatting-
operations) operation)

>
>     python reads.py <snip/> -q$queries <snip/>
>  

So you know how to do the redirection already, but how do you do the variable
expansion? You can use [the `format`
method](http://docs.python.org/library/stdtypes.html#str.format) (v2.6+):

    
    
    command = "python reads.py -r1 -pquery1.sql -q{0} -shotelspec -k6 -a5".format(queries)
    

You can alternatively use [the `%`
operator](http://docs.python.org/library/stdtypes.html#string-formatting-
operations):

    
    
    #since queries is a number, use %d as a placeholder
    command = "python reads.py -r1 -pquery1.sql -q%d -shotelspec -k6 -a5" % queries
    

* * *

### C-style loop → [Object-oriented-style
loop](http://docs.python.org/tutorial/controlflow.html#for-statements)

>
>     for ((r = 1; r < ($runs + 1); r++)) do done
>  

Looping in Python is different from C-style iteration. What happens in Python
is you iterate over an iterable object, like for example a list. Here, you are
trying to do something `runs` times, so you would do this:

    
    
    for r in range(runs):
      #loop body here
    

`range(runs)` is equivalent to `[0,1,...,runs-1]`, a list of `runs = 5`
integer elements. So you'll be repeating the body `runs` times. At every
cicle, `r` is assigned the next item of the list. This is thus completely
equivalent to what you are doing in Bash.

If you're feeling daring, use
[`xrange`](http://docs.python.org/library/functions.html#xrange) instead. It's
completely equivalent but uses more advanced language features (so it is
harder to explain in layman's terms) but consumes less resources.

* * *

### Output redirection → [the `subprocess`
module](http://docs.python.org/library/subprocess.html?highlight=subprocess#using-
the-subprocess-module)

The "tougher" part, if you will: executing a program and getting its output.
[Google to the
rescue!](http://www.google.com/search?q=how+to+get+the+output+of+a+program+python)
Obviously, the top hit is a stackoverflow question: [this
one](http://stackoverflow.com/questions/748028/how-to-get-output-of-exe-in-
python-script). You can hide all the complexity behind it with a simple
function:

    
    
    import subprocess, shlex
    def get_output_of(command):
      args = shlex.split(command)
      return subprocess.Popen(args,
                              stdout=subprocess.PIPE).communicate()[0]
      # this only returns stdout
    

So:

>
>     python reads.py -r1 -pquery1.sql -q$queries -shotelspec -k6 -a5 >>
> $outfile
>  

becomes:

    
    
    command = "python reads.py -r1 -pquery1.sql -q%s -shotelspec -k6 -a5" % queries
    read_result = get_output_of(command)
    

* * *

### Don't over-`subprocess`, batteries are included

Optionally, consider that you can get pretty much the same output of `date`
with the following:

    
    
    import time
    time_now = time.strftime("%c", time.localtime()) # Sat May 15 15:42:47 2010
    

(Note the absence of the time zone information. This should be the subject of
[another question](http://stackoverflow.com/questions/ask), if it is important
to you.)

* * *

### How your program should look like

The final result should then look like this:

    
    
    import subprocess, shlex, time
    def get_output_of(command):
      #... body of get_output_of
    #... more functions ...
    if __name__ = "__main__":
      #only execute the following if you are calling this .py file directly,
      #and not, say, importing it
      #... initialization ...
      with file("outputfile.txt", "a") as output_file: #alternative way to open files, v2.5+
        #... write date and other stuff ...
        for r in range(runs):
          #... loop body here ...
    

* * *

## Post scriptum

That must look pretty horrible when compared to the relatively simple and
short Bash script, right? Python is not a specialized language: it aims to do
everything reasonably well, but isn't built directly for running programs and
getting the output of those.

Still, you wouldn't _normally_ write a database engine in Bash, right? It's
different tools for different jobs. Here, unless you're planning to make some
changes that would be non-trivial to write with that language, [Ba]sh was
definitely the right choice.

