[Tutor] Pass arguments from bash script to embedded python script
Cameron Simpson
cs at cskk.id.au
Mon Oct 21 19:13:08 EDT 2019
On 21Oct2019 09:45, Stephen P. Molnar <s.molnar at sbcglobal.net> wrote:
>First of all, let me emphasize that this is not a homework assignment.
>I have a large number of data files form a Quantum Chemistry program
>which all have the same format.
>
>I have written a short python script to extract the data required for
>another program.
>
>>#!/usr/bin/env python3
>># -*- coding: utf-8 -*-
>>"""
>>
>>Created on Tue Sep 24 07:51:11 2019
>>
>>"""""
>>import numpy as np
>>
>>data = np.genfromtxt(fname, usecols=(1), skip_header=27,
>>skip_footer=1, encoding=None)
>>
>>print(data)
>>
>>np.savetxt('fname.dG', data, fmt='%.10g', header='fname1')
>>print(data)
Can you show us a bare command line invocation of this Python programme?
It is not clear to me what you expect to be in "fname"; I would have
assumed a filename, but your shell script suggests otherwise.
>and I have a bash script in which I have embedded the python script:
>
>>#!/bin/bash
Please, just say "shell script" instead of "bash script", and use
"#!/bin/sh". All systems have a /bin/sh, not all systems have a
/bin/bash, and nothing in your script needs anything that is special to
bash.
>># Run.dG.list_1
>>
>>while IFS= read -r d
>>do
>> python3 DeltaGTable_V_sw.py
>>done <ligand.list
Small recommendation: when you write a while loop in the shell which
reads from a file, you should avoid letting the commands _inside_ the
while loop also read from that file - they will consume it if they do
so, and your loop will terminate early. Rewrite the above loop like
this:
while IFS= read -r d <&3
do
python3 DeltaGTable_V_sw.py 3<&-
done 3<ligand.list
This attaches the "ligang.list" file to the "while" as file descriptor
3, reads from file descriptor 3, and arranges to _not_ pass file
descriptor 3 to the python programme. Much much safer.
>The ligand.list for the bash file have the format:
>>
>>>fname = ['C-VX3.log', '15-7.log', '14-7.log']
>>>fname1 = ['C-VX3', '15-7', '14-7'
>
>where fname and fname1 are three typical data files.
Are these 2 lines:
fname = ['C-VX3.log', '15-7.log', '14-7.log']
fname1 = ['C-VX3', '15-7', '14-7'
lines from the ligang.list file? i.e. actual Python assignment
statements?
>my problem is how do I pass the argument's in the two files from the
>bash script to the python script? It has been suggested to me that the
>solution is an implementation of the sys/.argv function but it seems
>that every reference that I can find goes the other way from python to
>bash.
Yah, because people call shell scripts or plain commands via subprocess
and routinely get this incorrect.
For your purpose, you have a shell variable $d containing a line from
the "ligand.list" file. I'd like to see an example of such a line, I
found your description unclear above.
However, to get you going...
You can pass that line as a single command line string to the Python
programme like this:
python3 DeltaGTable_V_sw.py "$d"
That will include any internal spaces etc in that single string,
courtesy of the quotes. Within the Python programm that string will be
sys.argv[1]; sys.argv being the command line invocation and sys.argv[0]
being the script name "DeltaGTable_V_sw.py".
You will need to "import sys" to get access to sys.argv of course.
That puts the parsing of the line in your Python code: you will need to
break it up on speaces or whatever is sesnsible (as I say, I'm unsure
what is really in the line). If "ligand.list" is just a text file with
filenames in it, one per line, you won't need to do anything to it -
just use the string.
Alternatively the shell script could break up the line on spaces if you
go:
python3 DeltaGTable_V_sw.py $d
This just omites the quotes, which causes the shell to grep $d into
"words". Supposing the line had:
C-VX3.log g15-7.log 14-7.log
then inside the Python programme sys.argv would have 4 strings:
DeltaGTable_V_sw.py
C-VX3.log
g15-7.log
14-7.log
and you can use sys.argv[1:] to access the latter 3 strings.
Your shell script is, however, so simple that you may as well just do it
_all_ in Python:
with open("ligand.list") as ligands:
for line in ligands:
# drop trailing newline and whitespace
text = line.rstrip()
... do whatever you want with text ...
This sidesteps the shell entirely.
Note that this kind of thing does get wordy in Python if your command
line stuff gets more comoplicated, and there will be a sweet spot where
it is nice to have a wrapper shell script like yours. I think you're
possibly just below that point (shell script too simple to bother with).
We can provide more detailed help if you can make the contents of
ligans.list more clear, and the desired invocation of the Python
programme more clear.
Cheers,
Cameron Simpson <cs at cskk.id.au>
More information about the Tutor
mailing list