Pass arguments as a list, see the very first code example in the docs:
import subprocess
subprocess.check_call(['/my/file/path/programname.sh', 'arg1', 'arg2', arg3])
If arg3 is not a string; convert it to string before passing to check_call(): arg3 = str(arg3).
I am trying to call a bash script via Popen but I am getting an error. bufsize must be an integer.
bash_args = '-a test -b 24 -c 15'
subprocess.Popen('/home/pi/bash.testsh', bash_args)The script does work. If I run via command line I get expected output, but via python I am getting errors.
Pass arguments as a list, see the very first code example in the docs:
import subprocess
subprocess.check_call(['/my/file/path/programname.sh', 'arg1', 'arg2', arg3])
If arg3 is not a string; convert it to string before passing to check_call(): arg3 = str(arg3).
subprocess.Popen(['/my/file/path/programname.sh arg1 arg2 %s' % arg3], shell = True).
If you use shell = True the script and its arguments have to be passed as a string. Any other elements in the args sequence will be treated as arguments to the shell.
You can find the complete docs at http://docs.python.org/2/library/subprocess.html#subprocess.Popen.
How to pass command line arguments to bash/python script task template
scripting - bash script to run a python command with arguments in batch - Unix & Linux Stack Exchange
shell script - Unable to pass a bash variable as a python argument in bash - Unix & Linux Stack Exchange
Using a bash script to execute python script with arguments - Stack Overflow
Videos
To execute a python script in a bash script you need to call the same command that you would within a terminal. For instance
> python python_script.py var1 var2
To access these variables within python you will need
import sys
print(sys.argv[0]) # prints python_script.py
print(sys.argv[1]) # prints var1
print(sys.argv[2]) # prints var2
Beside sys.argv, also take a look at the argparse module, which helps define options and arguments for scripts.
The argparse module makes it easy to write user-friendly command-line interfaces.
The python equivalent of the shell's positional parameter array $1, $2 etc. is sys.argv
So:
#!/usr/bin/env python
import sys
def getPermutation(s, prefix=''):
if len(s) == 0:
print prefix
for i in range(len(s)):
getPermutation(s[0:i]+s[i+1:len(s)],prefix+s[i] )
getPermutation(sys.argv[1],'')
then
$ ./foo.py abcd
abcd
abdc
acbd
acdb
adbc
adcb
bacd
badc
bcad
bcda
bdac
bdca
cabd
cadb
cbad
cbda
cdab
cdba
dabc
dacb
dbac
dbca
dcab
dcba
Lots of ways to parameterize python. positional args, env variables, and named args. Env variables:
import os and use the getenv like:
fw_main_width =os.getenv('FW_MAIN_WIDTH', fw_main_width)
Where the second parameter is the default for the env variable not being set.
Positional args:
Use the sys.argc, sys.argv[n] after you import sys.
Named parameters:
Or for named parameters,(what you asked)
import argparse
then describe the possible parameters:
parser = argparse.ArgumentParser(description = "Project", fromfile_prefix_chars='@')
parser.add_argument("-V", "--version", help="show program version", action="store_true")
parser.add_argument("-W", "--width", help="set main screen width")
read arguments from the command line
args = parser.parse_args()
and use them as args.width etc.
You can also use the sys module. Here is an example :
import sys
first_arg = sys.argv[1]
second_arg = sys.argv[2]
def greetings(word1=first_arg, word2=second_arg):
print("{} {}".format(word1, word2))
if __name__ == "__main__":
greetings()
greetings("Bonjour", "monde")
It has the behavior your are looking for :
$ python parse_args.py Hello world
Hello world
Bonjour monde
Python provides more than one way to parse arguments. The best choice is using the argparse module, which has many features you can use.
So you have to parse arguments in your code and try to catch and fetch the arguments inside your code.
You can't just pass arguments through terminal without parsing them from your code.
Replace test with "${filename%.faa}" to get the name of the file with .faa removed. You should also quote "${filename}" to avoid problems in case of filenames with spaces.
#!/bin/sh
for filename in *.faa ; do
python predict_genome.py \
--fasta_path /Users/mvalvano/DeepSecE/myruns/"${filename}" \
--model_location /Users/mvalvano/DeepSecE/model/checkpoint.pt \
--data_dir data \
--out_dir myruns/"${filename%.faa}" \
--save_attn --no_cuda
done
exit 0
With input files
bar.faa
foo.faa
the script will run
python predict_genome.py --fasta_path /Users/mvalvano/DeepSecE/myruns/bar.faa --model_location /Users/mvalvano/DeepSecE/model/checkpoint.pt --data_dir data --out_dir myruns/bar --save_attn --no_cuda
python predict_genome.py --fasta_path /Users/mvalvano/DeepSecE/myruns/foo.faa --model_location /Users/mvalvano/DeepSecE/model/checkpoint.pt --data_dir data --out_dir myruns/foo --save_attn --no_cuda
Possible problems with this script:
Since you specify --fasta_path /Users/mvalvano/DeepSecE/myruns/"${filename}", your script will only work without error if the current directory is /Users/mvalvano/DeepSecE/myruns/ or if this directory contains at least the same set of *.faa files as the current directory. (*.faa will expand to the file names in the current directory.)
When /Users/mvalvano/DeepSecE/myruns/ is the current directory, the argument --out_dir myruns/foo might expect or create a directory /Users/mvalvano/DeepSecE/myruns/myruns/foo with double myruns.
Maybe it would make more sense to write it as:
#! /bin/zsh -
topdir=/Users/mvalvano/DeepSecE
ret=0
for filename in $topdir/myruns/*.faa(N); do
outdir=$filename:r
mkdir -p -- $outdir &&
python -- $topdir/predict_genome.py \
--fasta_path $filename \
--model_location $topdir/model/checkpoint.pt \
--data_dir $topdir/data \
--out_dir $outdir \
--save_attn --no_cuda || ret=$?
done
exit $ret
Where we use only absolute paths removing the doubt about what relative paths are relative to.
(here switching to zsh (since that /Users suggests macos) for its :rootname modifier (from csh), its Nullglob qualifier and to remove the need to quote all expansions).
Perhaps the aws bash command is returning non-printable characters that you don't see with print(). Try removing them with tr:
FOLDER=$(./aws get $BUCKET"/location.txt" | tr -cd "[:print:]")
Try to put $FOLDER inside double quotes:
python script.py "$FOLDER"
Change the first line of your script to
#!/usr/bin/env python
This should work.
And be more clear on your questions.
As @drs said, your question is still incomplete:
- Your examples are still vague and with flaws, like what is the correct name of your script, is it
pythonscriptors3download? - Is it "work as expected" supposed to have a blank value for
bucket.get_location()?
Hello,
I'm trying to write a bash wrapper script (in Linux) to run a python program in background, allowing the user to logout keeping the script running. I'm trying to do it with nohup. I'm also trying to support a proper ' escape to support space in the arguments (see below).
My goal is that the bash script works like a bash command, passing to the python code all the command line arguments entered by the user.
Here is how I run the python code, without going to background:
$ python3 /scripts/pyprog.py --arg1='argument 1','argument 2','argument 3' --arg2='argument 4','argument 5'
I did something like:
#!/bin/bash
NOHUP=$(which nohup)
ARGS=($*)
exec "${NOHUP} python3 /scripts/pyprog.py ${ARGS[@]} &"
However, bash tells it cannot run that exec line. I'm clearly missing some point :-) I would very much appreciate any help.
Thanks!